SongBrowser.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  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.Original;
  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. songList.ForEach(x => _log.Debug(x.levelId));
  271. switch(_settings.sortMode)
  272. {
  273. case SongSortMode.Favorites:
  274. _log.Debug(" Sorting list as favorites");
  275. songList = songList
  276. .AsQueryable()
  277. .OrderBy(x => x.authorName)
  278. .OrderBy(x => x.songName)
  279. .OrderBy(x => _settings.favorites.Contains(x.levelId) == false).ThenBy(x => x.songName)
  280. .ToList();
  281. break;
  282. case SongSortMode.Original:
  283. _log.Debug(" Sorting list as original");
  284. // Invert the weights from the game so we can order by descending and make LINQ work with us...
  285. /* Level4, Level2, Level9, Level5, Level10, Level6, Level7, Level1, Level3, Level8, */
  286. Dictionary<string, int> weights = new Dictionary<string, int>();
  287. weights["Level4"] = 10;
  288. weights["Level2"] = 9;
  289. weights["Level9"] = 8;
  290. weights["Level5"] = 7;
  291. weights["Level10"] = 6;
  292. weights["Level6"] = 5;
  293. weights["Level7"] = 4;
  294. weights["Level1"] = 3;
  295. weights["Level3"] = 2;
  296. weights["Level8"] = 1;
  297. songList = songList
  298. .AsQueryable()
  299. .OrderByDescending(x => weights.ContainsKey(x.levelId) ? weights[x.levelId] : 0)
  300. .ThenBy(x => x.songName)
  301. .ToList();
  302. break;
  303. case SongSortMode.Default:
  304. default:
  305. _log.Debug(" Sorting list as default");
  306. songList = songList
  307. .AsQueryable()
  308. .OrderBy(x => x.authorName)
  309. .ThenBy(x => x.songName).ToList();
  310. break;
  311. }
  312. //songList.ForEach(x => _log.Debug(x.songName));
  313. OverwriteSongList(songList);
  314. }
  315. /// <summary>
  316. /// Try to refresh the song list. Broken for now.
  317. /// </summary>
  318. public void RefreshSongList()
  319. {
  320. _log.Debug("Trying to refresh song list!");
  321. // Forcefully refresh the song view
  322. var newSongList = AcquireSongList();
  323. SongListTableView songTableView = _songListViewController.GetComponentInChildren<SongListTableView>();
  324. ReflectionUtil.SetPrivateField(songTableView, "_levels", newSongList.ToArray());
  325. TableView tableView = ReflectionUtil.GetPrivateField<TableView>(songTableView, "_tableView");
  326. tableView.ReloadData();
  327. songTableView.ClearSelection();
  328. _songListViewController.SelectSong(0);
  329. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  330. RefreshUI();
  331. //Action showMethod = delegate () { };
  332. //_songSelectionMasterView.DismissModalViewController(showMethod);
  333. }
  334. /// <summary>
  335. /// Adjust the UI colors.
  336. /// </summary>
  337. public void RefreshUI()
  338. {
  339. UIBuilder.SetButtonBorder(ref _favoriteButton, Color.black);
  340. UIBuilder.SetButtonBorder(ref _defaultButton, Color.black);
  341. UIBuilder.SetButtonBorder(ref _originalButton, Color.black);
  342. switch (_settings.sortMode)
  343. {
  344. case SongSortMode.Favorites:
  345. UIBuilder.SetButtonBorder(ref _favoriteButton, Color.red);
  346. break;
  347. case SongSortMode.Default:
  348. UIBuilder.SetButtonBorder(ref _defaultButton, Color.red);
  349. break;
  350. case SongSortMode.Original:
  351. UIBuilder.SetButtonBorder(ref _originalButton, Color.red);
  352. break;
  353. default:
  354. break;
  355. }
  356. }
  357. /// <summary>
  358. /// Map some key presses directly to UI interactions to make testing easier.
  359. /// </summary>
  360. private void Update()
  361. {
  362. if (Input.GetKeyDown(KeyCode.T))
  363. {
  364. _settings.sortMode = SongSortMode.Original;
  365. ProcessSongList();
  366. RefreshSongList();
  367. }
  368. if (Input.GetKeyDown(KeyCode.Z))
  369. {
  370. Button _buttonInstance = Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == "SoloButton"));
  371. _buttonInstance.onClick.Invoke();
  372. }
  373. if (Input.GetKeyDown(KeyCode.X))
  374. {
  375. Button _buttonInstance = Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == "FreePlayButton"));
  376. _buttonInstance.onClick.Invoke();
  377. }
  378. if (Input.GetKeyDown(KeyCode.C))
  379. {
  380. _songListViewController.SelectSong(0);
  381. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  382. DifficultyViewController _difficultyViewController = Resources.FindObjectsOfTypeAll<DifficultyViewController>().First();
  383. _difficultyViewController.SelectDifficulty(LevelStaticData.Difficulty.Hard);
  384. _songSelectionMasterView.HandleDifficultyViewControllerDidSelectDifficulty(_difficultyViewController);
  385. }
  386. if (Input.GetKeyDown(KeyCode.V))
  387. {
  388. _songSelectionMasterView.HandleSongDetailViewControllerDidPressPlayButton(_songDetailViewController);
  389. }
  390. if (Input.GetKeyDown(KeyCode.N))
  391. {
  392. int newIndex = _songSelectionMasterView.GetSelectedSongIndex() - 1;
  393. _songListViewController.SelectSong(newIndex);
  394. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  395. SongListTableView songTableView = Resources.FindObjectsOfTypeAll<SongListTableView>().First();
  396. _songListViewController.HandleSongListTableViewDidSelectRow(songTableView, newIndex);
  397. }
  398. if (Input.GetKeyDown(KeyCode.M))
  399. {
  400. int newIndex = _songSelectionMasterView.GetSelectedSongIndex() + 1;
  401. _songListViewController.SelectSong(newIndex);
  402. _songSelectionMasterView.HandleSongListDidSelectSong(_songListViewController);
  403. SongListTableView songTableView = Resources.FindObjectsOfTypeAll<SongListTableView>().First();
  404. _songListViewController.HandleSongListTableViewDidSelectRow(songTableView, newIndex);
  405. }
  406. if (Input.GetKeyDown(KeyCode.F))
  407. {
  408. ToggleSongInFavorites();
  409. }
  410. }
  411. }
  412. }