SongBrowser.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. using UnityEngine;
  2. using System.Linq;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Security.Cryptography;
  6. using UnityEngine.Events;
  7. using UnityEngine.SceneManagement;
  8. using UnityEngine.UI;
  9. using System.Text;
  10. using HMUI;
  11. using System.Text.RegularExpressions;
  12. namespace SongBrowserPlugin
  13. {
  14. public class SongBrowser : MonoBehaviour
  15. {
  16. public static readonly UnityEvent SongsLoaded = new UnityEvent();
  17. public const int MenuIndex = 1;
  18. private Logger _log = new Logger("SongBrowserPlugin");
  19. private SongSelectionMasterViewController _songSelectionMasterView;
  20. private SongDetailViewController _songDetailViewController;
  21. private SongListViewController _songListViewController;
  22. private MainMenuViewController _mainMenuViewController;
  23. private List<Sprite> _icons = new List<Sprite>();
  24. private Button _buttonInstance;
  25. private Button _favoriteButton;
  26. private Button _defaultButton;
  27. private Button _originalButton;
  28. private Button _addFavoriteButton;
  29. private RectTransform _songSelectRectTransform;
  30. private SongBrowserSettings _settings;
  31. /// <summary>
  32. /// Unity OnLoad
  33. /// </summary>
  34. public static void OnLoad()
  35. {
  36. if (Instance != null) return;
  37. new GameObject("Song Browser").AddComponent<SongBrowser>();
  38. }
  39. public static SongBrowser Instance;
  40. /// <summary>
  41. /// Builds the UI for this plugin.
  42. /// </summary>
  43. private void Awake()
  44. {
  45. Instance = this;
  46. _settings = SongBrowserSettings.Load();
  47. AcquireUIElements();
  48. CreateUI();
  49. SceneManager.activeSceneChanged += SceneManagerOnActiveSceneChanged;
  50. SceneManagerOnActiveSceneChanged(new Scene(), new Scene());
  51. DontDestroyOnLoad(gameObject);
  52. }
  53. /// <summary>
  54. /// Get a handle to the view controllers we are going to add elements to.
  55. /// </summary>
  56. public void AcquireUIElements()
  57. {
  58. foreach (Sprite sprite in Resources.FindObjectsOfTypeAll<Sprite>())
  59. {
  60. _icons.Add(sprite);
  61. }
  62. try
  63. {
  64. _buttonInstance = Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == "PlayButton"));
  65. _mainMenuViewController = Resources.FindObjectsOfTypeAll<MainMenuViewController>().First();
  66. _songSelectionMasterView = Resources.FindObjectsOfTypeAll<SongSelectionMasterViewController>().First();
  67. _songDetailViewController = Resources.FindObjectsOfTypeAll<SongDetailViewController>().First();
  68. _songListViewController = Resources.FindObjectsOfTypeAll<SongListViewController>().First();
  69. _songSelectRectTransform = _songListViewController.transform as RectTransform;
  70. }
  71. catch (Exception e)
  72. {
  73. _log.Exception("Exception AcquireUIElements(): " + e);
  74. }
  75. }
  76. /// <summary>
  77. /// Builds the SongBrowser UI
  78. /// </summary>
  79. public void CreateUI()
  80. {
  81. _log.Debug("CreateUI");
  82. // _icons.ForEach(i => Console.WriteLine(i.ToString()));
  83. try
  84. {
  85. // Create Sorting Songs By-Buttons
  86. // Fav button
  87. RectTransform rect = _songDetailViewController.transform as RectTransform; // _songDetailViewController.GetComponent<RectTransform>();
  88. _favoriteButton = UIBuilder.CreateUIButton(rect, "PlayButton", _buttonInstance);
  89. _favoriteButton.interactable = true;
  90. (_favoriteButton.transform as RectTransform).anchoredPosition = new Vector2(30f, 74f);
  91. (_favoriteButton.transform as RectTransform).sizeDelta = new Vector2(15f, 10f);
  92. UIBuilder.SetButtonText(ref _favoriteButton, "Fav");
  93. //UIBuilder.SetButtonIconEnabled(ref _favoriteButton, false);
  94. UIBuilder.SetButtonIcon(ref _favoriteButton, _icons.First(x => (x.name == "AllDirectionsIcon")));
  95. _favoriteButton.onClick.RemoveAllListeners();
  96. _favoriteButton.onClick.AddListener(delegate () {
  97. _log.Debug("Sort button - favorites - pressed.");
  98. _settings.sortMode = SongSortMode.Favorites;
  99. ProcessSongList();
  100. RefreshSongList();
  101. });
  102. // Default button
  103. _defaultButton = UIBuilder.CreateUIButton(rect, "PlayButton", _buttonInstance);
  104. _defaultButton.interactable = true;
  105. (_defaultButton.transform as RectTransform).anchoredPosition = new Vector2(15f, 74f);
  106. (_defaultButton.transform as RectTransform).sizeDelta = new Vector2(15f, 10f);
  107. UIBuilder.SetButtonText(ref _defaultButton, "Def");
  108. //UIBuilder.SetButtonIconEnabled(ref _defaultButton, false);
  109. UIBuilder.SetButtonIcon(ref _defaultButton, _icons.First(x => (x.name == "SettingsIcon")));
  110. _defaultButton.onClick.RemoveAllListeners();
  111. _defaultButton.onClick.AddListener(delegate () {
  112. _log.Debug("Sort button - default - pressed.");
  113. _settings.sortMode = SongSortMode.Default;
  114. ProcessSongList();
  115. RefreshSongList();
  116. });
  117. // Original button
  118. _originalButton = UIBuilder.CreateUIButton(rect, "PlayButton", _buttonInstance);
  119. _originalButton.interactable = true;
  120. (_originalButton.transform as RectTransform).anchoredPosition = new Vector2(0f, 74f);
  121. (_originalButton.transform as RectTransform).sizeDelta = new Vector2(15f, 10f);
  122. UIBuilder.SetButtonText(ref _originalButton, "Org");
  123. //UIBuilder.SetButtonIconEnabled(ref _originalButton, false);
  124. UIBuilder.SetButtonIcon(ref _originalButton, _icons.First(x => (x.name == "SoloIcon")));
  125. _originalButton.onClick.RemoveAllListeners();
  126. _originalButton.onClick.AddListener(delegate () {
  127. _log.Debug("Sort button - original - pressed.");
  128. _settings.sortMode = SongSortMode.Default;
  129. ProcessSongList();
  130. RefreshSongList();
  131. });
  132. // Creaate Add to Favorites Button
  133. RectTransform transform = _songDetailViewController.transform as RectTransform;
  134. _addFavoriteButton = UIBuilder.CreateUIButton(transform, "QuitButton", _buttonInstance);
  135. (_addFavoriteButton.transform as RectTransform).anchoredPosition = new Vector2(40f, 0f);
  136. (_addFavoriteButton.transform as RectTransform).sizeDelta = new Vector2(25f, 10f);
  137. UIBuilder.SetButtonText(ref _addFavoriteButton, "+1");
  138. UIBuilder.SetButtonIcon(ref _addFavoriteButton, _icons.First(x => (x.name == "AllDirectionsIcon")));
  139. _addFavoriteButton.onClick.RemoveAllListeners();
  140. _addFavoriteButton.onClick.AddListener(delegate () {
  141. ToggleSongInFavorites();
  142. });
  143. RefreshUI();
  144. }
  145. catch (Exception e)
  146. {
  147. _log.Exception("Exception CreateUI: " + e.Message);
  148. }
  149. }
  150. /// <summary>
  151. /// Bind to some UI events.
  152. /// </summary>
  153. /// <param name="arg0"></param>
  154. /// <param name="scene"></param>
  155. private void SceneManagerOnActiveSceneChanged(Scene arg0, Scene scene)
  156. {
  157. //_log.Debug("scene.buildIndex==" + scene.buildIndex);
  158. try
  159. {
  160. if (scene.buildIndex == SongBrowser.MenuIndex || scene.buildIndex == -1)
  161. {
  162. _log.Debug("SceneManagerOnActiveSceneChanged - binding to UI");
  163. SongLoaderPlugin.SongLoader.SongsLoaded.AddListener(OnSongLoaderLoadedSongs);
  164. //SongListTableView table = _songListViewController.GetComponentInChildren<SongListTableView>();
  165. //MainMenuViewController _mainMenuViewController = Resources.FindObjectsOfTypeAll<MainMenuViewController>().First();
  166. _songListViewController.didSelectSongEvent += OnDidSelectSongEvent;
  167. }
  168. }
  169. catch (Exception e)
  170. {
  171. _log.Exception("Exception during scene change: " + e);
  172. }
  173. }
  174. /// <summary>
  175. /// Song Loader has loaded the songs, lets sort them.
  176. /// </summary>
  177. private void OnSongLoaderLoadedSongs()
  178. {
  179. _log.Debug("--OnSongLoaderLoadedSongs");
  180. ProcessSongList();
  181. RefreshSongList();
  182. }
  183. /// <summary>
  184. /// Adjust UI based on song selected.
  185. /// </summary>
  186. /// <param name="songListViewController"></param>
  187. private void OnDidSelectSongEvent(SongListViewController songListViewController)
  188. {
  189. int selectedIndex = _songSelectionMasterView.GetSelectedSongIndex();
  190. _log.Debug("Selected song index: " + selectedIndex);
  191. if (selectedIndex < 0)
  192. {
  193. _log.Debug("No song selected, index is less than zero.");
  194. return;
  195. }
  196. LevelStaticData level = _songSelectionMasterView.GetLevelStaticDataForSelectedSong();
  197. if (level == null)
  198. {
  199. _log.Debug("No song selected?");
  200. return;
  201. }
  202. if (_settings == null)
  203. {
  204. _log.Debug("Settings not instantiated yet?");
  205. return;
  206. }
  207. if (_settings.favorites.Contains(level.levelId))
  208. {
  209. UIBuilder.SetButtonText(ref _addFavoriteButton, "-1");
  210. }
  211. else
  212. {
  213. UIBuilder.SetButtonText(ref _addFavoriteButton, "+1");
  214. }
  215. }
  216. /*private void OnDidSelectSongRow(SongListTableView table, int index)
  217. {
  218. Console.WriteLine("OnDidSelectSongRow");
  219. }*/
  220. /// <summary>
  221. /// Add/Remove song from favorites depending on if it already exists.
  222. /// </summary>
  223. private void ToggleSongInFavorites()
  224. {
  225. LevelStaticData songInfo = _songSelectionMasterView.GetLevelStaticDataForSelectedSong();
  226. if (_settings.favorites.Contains(songInfo.levelId))
  227. {
  228. _log.Info("Remove {0} from favorites", songInfo.name);
  229. _settings.favorites.Remove(songInfo.levelId);
  230. UIBuilder.SetButtonText(ref _addFavoriteButton, "+1");
  231. }
  232. else
  233. {
  234. _log.Info("Add {0} to favorites", songInfo.name);
  235. _settings.favorites.Add(songInfo.levelId);
  236. UIBuilder.SetButtonText(ref _addFavoriteButton, "-1");
  237. }
  238. _settings.Save();
  239. ProcessSongList();
  240. }
  241. /// <summary>
  242. /// Fetch the existing song list.
  243. /// </summary>
  244. /// <returns></returns>
  245. public List<LevelStaticData> AcquireSongList()
  246. {
  247. _log.Debug("AcquireSongList()");
  248. var gameScenesManager = Resources.FindObjectsOfTypeAll<GameScenesManager>().FirstOrDefault();
  249. var gameDataModel = PersistentSingleton<GameDataModel>.instance;
  250. List<LevelStaticData> songList = gameDataModel.gameStaticData.worldsData[0].levelsData.ToList();
  251. _log.Debug("SongBrowser songList.Count={0}", songList.Count);
  252. return songList;
  253. }
  254. /// <summary>
  255. /// Helper to overwrite the existing song list and refresh it.
  256. /// </summary>
  257. /// <param name="newSongList"></param>
  258. public void OverwriteSongList(List<LevelStaticData> newSongList)
  259. {
  260. var gameDataModel = PersistentSingleton<GameDataModel>.instance;
  261. ReflectionUtil.SetPrivateField(gameDataModel.gameStaticData.worldsData[0], "_levelsData", newSongList.ToArray());
  262. }
  263. /// <summary>
  264. /// Sort the song list based on the settings.
  265. /// </summary>
  266. public void ProcessSongList()
  267. {
  268. _log.Debug("ProcessSongList()");
  269. List<LevelStaticData> songList = AcquireSongList();
  270. switch(_settings.sortMode)
  271. {
  272. case SongSortMode.Favorites:
  273. _log.Debug(" Sorting list as favorites");
  274. songList = songList
  275. .AsQueryable()
  276. .OrderBy(x => x.authorName)
  277. .OrderBy(x => x.songName)
  278. .OrderBy(x => _settings.favorites.Contains(x.levelId) == false).ThenBy(x => x.songName)
  279. .ToList();
  280. break;
  281. case SongSortMode.Original:
  282. _log.Debug(" Sorting list as original");
  283. songList = songList
  284. .AsQueryable()
  285. .OrderBy(x => !x.levelId.StartsWith("Level"))
  286. .ThenBy(x => x.levelId.StartsWith("Level"))
  287. .ThenBy(x => x.name)
  288. .ToList();
  289. break;
  290. case SongSortMode.Default:
  291. default:
  292. _log.Debug(" Sorting list as default");
  293. songList = songList
  294. .AsQueryable()
  295. .OrderBy(x => x.authorName)
  296. .ThenBy(x => x.songName).ToList();
  297. break;
  298. }
  299. //songList.ForEach(x => _log.Debug(x.songName));
  300. OverwriteSongList(songList);
  301. }
  302. /// <summary>
  303. /// Try to refresh the song list. Broken for now.
  304. /// </summary>
  305. public void RefreshSongList()
  306. {
  307. _log.Debug("Trying to refresh song list!");
  308. // Forcefully refresh the song view
  309. var newSongList = AcquireSongList();
  310. SongListTableView songTableView = _songListViewController.GetComponentInChildren<SongListTableView>();
  311. ReflectionUtil.SetPrivateField(songTableView, "_levels", newSongList.ToArray());
  312. TableView tableView = ReflectionUtil.GetPrivateField<TableView>(songTableView, "_tableView");
  313. tableView.ReloadData();
  314. songTableView.ClearSelection();
  315. _songListViewController.SelectSong(0);
  316. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  317. RefreshUI();
  318. //Action showMethod = delegate () { };
  319. //_songSelectionMasterView.DismissModalViewController(showMethod);
  320. }
  321. /// <summary>
  322. /// Adjust the UI colors.
  323. /// </summary>
  324. public void RefreshUI()
  325. {
  326. UIBuilder.SetButtonBorder(ref _favoriteButton, Color.black);
  327. UIBuilder.SetButtonBorder(ref _defaultButton, Color.black);
  328. UIBuilder.SetButtonBorder(ref _originalButton, Color.black);
  329. switch (_settings.sortMode)
  330. {
  331. case SongSortMode.Favorites:
  332. UIBuilder.SetButtonBorder(ref _favoriteButton, Color.red);
  333. break;
  334. case SongSortMode.Default:
  335. UIBuilder.SetButtonBorder(ref _defaultButton, Color.red);
  336. break;
  337. case SongSortMode.Original:
  338. UIBuilder.SetButtonBorder(ref _originalButton, Color.red);
  339. break;
  340. default:
  341. break;
  342. }
  343. }
  344. /// <summary>
  345. /// Map some key presses directly to UI interactions to make testing easier.
  346. /// </summary>
  347. private void Update()
  348. {
  349. if (Input.GetKeyDown(KeyCode.T))
  350. {
  351. _settings.sortMode = SongSortMode.Original;
  352. ProcessSongList();
  353. RefreshSongList();
  354. }
  355. if (Input.GetKeyDown(KeyCode.Z))
  356. {
  357. Button _buttonInstance = Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == "SoloButton"));
  358. _buttonInstance.onClick.Invoke();
  359. }
  360. if (Input.GetKeyDown(KeyCode.X))
  361. {
  362. Button _buttonInstance = Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == "FreePlayButton"));
  363. _buttonInstance.onClick.Invoke();
  364. }
  365. if (Input.GetKeyDown(KeyCode.C))
  366. {
  367. _songListViewController.SelectSong(0);
  368. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  369. DifficultyViewController _difficultyViewController = Resources.FindObjectsOfTypeAll<DifficultyViewController>().First();
  370. _difficultyViewController.SelectDifficulty(LevelStaticData.Difficulty.Hard);
  371. _songSelectionMasterView.HandleDifficultyViewControllerDidSelectDifficulty(_difficultyViewController);
  372. }
  373. if (Input.GetKeyDown(KeyCode.V))
  374. {
  375. _songSelectionMasterView.HandleSongDetailViewControllerDidPressPlayButton(_songDetailViewController);
  376. }
  377. if (Input.GetKeyDown(KeyCode.N))
  378. {
  379. int newIndex = _songSelectionMasterView.GetSelectedSongIndex() - 1;
  380. _songListViewController.SelectSong(newIndex);
  381. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  382. SongListTableView songTableView = Resources.FindObjectsOfTypeAll<SongListTableView>().First();
  383. _songListViewController.HandleSongListTableViewDidSelectRow(songTableView, newIndex);
  384. }
  385. if (Input.GetKeyDown(KeyCode.M))
  386. {
  387. int newIndex = _songSelectionMasterView.GetSelectedSongIndex() + 1;
  388. _songListViewController.SelectSong(newIndex);
  389. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  390. SongListTableView songTableView = Resources.FindObjectsOfTypeAll<SongListTableView>().First();
  391. _songListViewController.HandleSongListTableViewDidSelectRow(songTableView, newIndex);
  392. }
  393. if (Input.GetKeyDown(KeyCode.F))
  394. {
  395. ToggleSongInFavorites();
  396. }
  397. }
  398. }
  399. }