Przeglądaj źródła

Merge branch 'devel'

Stephen Damm 6 lat temu
rodzic
commit
332e4dc35a
38 zmienionych plików z 255 dodań i 213 usunięć
  1. 1 1
      README.md
  2. BIN
      Screenshot.png
  3. 1 1
      SongBrowserPlugin/DataAccess/BeatSaverApi/BeatSaverApiResults.cs
  4. 1 1
      SongBrowserPlugin/DataAccess/FileOperationApiWrapper.cs
  5. 1 1
      SongBrowserPlugin/DataAccess/LoadScripts.cs
  6. 1 1
      SongBrowserPlugin/DataAccess/Network/CacheableDownloadHandler.cs
  7. 1 1
      SongBrowserPlugin/DataAccess/Network/CacheableDownloadHandlerScoreSaberData.cs
  8. 4 4
      SongBrowserPlugin/DataAccess/Network/Downloader.cs
  9. 4 4
      SongBrowserPlugin/DataAccess/Playlist.cs
  10. 3 3
      SongBrowserPlugin/DataAccess/ScoreSaberDatabase.cs
  11. 2 2
      SongBrowserPlugin/DataAccess/ScrappedData.cs
  12. 28 24
      SongBrowserPlugin/DataAccess/SongBrowserModel.cs
  13. 6 6
      SongBrowserPlugin/DataAccess/SongBrowserSettings.cs
  14. 1 1
      SongBrowserPlugin/Internals/BSEvents.cs
  15. 4 3
      SongBrowserPlugin/Internals/CustomHelpers.cs
  16. 2 2
      SongBrowserPlugin/Logging/Logger.cs
  17. 6 6
      SongBrowserPlugin/Plugin.cs
  18. 3 3
      SongBrowserPlugin/PluginConfig.cs
  19. 4 4
      SongBrowserPlugin/Properties/AssemblyInfo.cs
  20. 33 23
      SongBrowserPlugin/SongBrowserPlugin.csproj
  21. 1 1
      SongBrowserPlugin/SongBrowserPlugin.sln
  22. 6 6
      SongBrowserPlugin/SongBrowserApplication.cs
  23. 1 1
      SongBrowserPlugin/UI/BackButtonNavigationController.cs
  24. 3 3
      SongBrowserPlugin/UI/Base64Sprites.cs
  25. 82 67
      SongBrowserPlugin/UI/Browser/SongBrowserUI.cs
  26. 2 2
      SongBrowserPlugin/UI/Browser/SongFilterButton.cs
  27. 2 2
      SongBrowserPlugin/UI/Browser/SongSortButton.cs
  28. 3 3
      SongBrowserPlugin/UI/DownloadQueue/DownloadQueueTableCell.cs
  29. 3 3
      SongBrowserPlugin/UI/DownloadQueue/DownloadQueueViewController.cs
  30. 2 2
      SongBrowserPlugin/UI/Keyboard/CustomUIKeyboard.cs
  31. 1 1
      SongBrowserPlugin/UI/Keyboard/SearchKeyboardViewController.cs
  32. 7 4
      SongBrowserPlugin/UI/Playlists/PlaylistDetailViewController.cs
  33. 6 6
      SongBrowserPlugin/UI/Playlists/PlaylistFlowCoordinator.cs
  34. 15 12
      SongBrowserPlugin/UI/Playlists/PlaylistSelectionListViewController.cs
  35. 1 1
      SongBrowserPlugin/UI/ProgressBar.cs
  36. 1 1
      SongBrowserPlugin/UI/SceneEvents.cs
  37. 4 4
      SongBrowserPlugin/UI/ScoreSaberDatabaseDownloader.cs
  38. 9 3
      SongBrowserPlugin/UI/UIBuilder.cs

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-# BeatSaberSongBrowser
+# Beat Saber SongBrowser
 A plugin for customizing the in-game song browser.
 
 *This mod works on both the Steam and Oculus Store versions.*

BIN
Screenshot.png


+ 1 - 1
SongBrowserPlugin/DataAccess/BeatSaverApi/BeatSaverApiResults.cs

@@ -6,7 +6,7 @@ using SongLoaderPlugin.OverrideClasses;
 
 
 // From: https://github.com/andruzzzhka/BeatSaverDownloader
-namespace SongBrowserPlugin.DataAccess.BeatSaverApi
+namespace SongBrowser.DataAccess.BeatSaverApi
 {
     public enum SongQueueState { Queued, Downloading, Downloaded, Error };
 

+ 1 - 1
SongBrowserPlugin/DataAccess/FileOperationApiWrapper.cs

@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace SongBrowserPlugin.DataAccess
+namespace SongBrowser.DataAccess
 {
     public class FileOperationAPIWrapper
     {

+ 1 - 1
SongBrowserPlugin/DataAccess/LoadScripts.cs

@@ -7,7 +7,7 @@ using System.Linq;
 using UnityEngine;
 
 // From: https://github.com/andruzzzhka/BeatSaverDownloader
-namespace SongBrowserPlugin.DataAccess
+namespace SongBrowser.DataAccess
 {
     class LoadScripts
     {

+ 1 - 1
SongBrowserPlugin/DataAccess/Network/CacheableDownloadHandler.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System;
 using UnityEngine;
 
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
 // Modified Version of:
 // https://github.com/mob-sakai/AssetSystem/blob/master/Assets/Mobcast/Coffee/AssetSystem/CacheableDownloadHandler.cs

+ 1 - 1
SongBrowserPlugin/DataAccess/Network/CacheableDownloadHandlerScoreSaberData.cs

@@ -1,7 +1,7 @@
 using Mobcast.Coffee.AssetSystem;
 using UnityEngine.Networking;
 
-namespace SongBrowserPlugin.DataAccess.Network
+namespace SongBrowser.DataAccess.Network
 {
     /// <summary>
 	/// Cacheable download handler for score saber tsv file.

+ 4 - 4
SongBrowserPlugin/DataAccess/Network/Downloader.cs

@@ -1,6 +1,6 @@
 using SimpleJSON;
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
+using SongBrowser.DataAccess;
+using SongBrowser.DataAccess.BeatSaverApi;
 using SongLoaderPlugin;
 using SongLoaderPlugin.OverrideClasses;
 using System;
@@ -15,9 +15,9 @@ using System.Threading;
 using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.Networking;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin
+namespace SongBrowser
 {
     // https://github.com/andruzzzhka/BeatSaverDownloader/blob/master/BeatSaverDownloader/Misc/SongDownloader.cs
     public class SongDownloader : MonoBehaviour

+ 4 - 4
SongBrowserPlugin/DataAccess/Playlist.cs

@@ -1,6 +1,6 @@
 using Newtonsoft.Json;
 using SimpleJSON;
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
+using SongBrowser.DataAccess.BeatSaverApi;
 using SongLoaderPlugin;
 using System;
 using System.Collections;
@@ -10,10 +10,10 @@ using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
 using UnityEngine;
-using Logger = SongBrowserPlugin.Logging.Logger;
-using Sprites = SongBrowserPlugin.UI.Base64Sprites;
+using Logger = SongBrowser.Logging.Logger;
+using Sprites = SongBrowser.UI.Base64Sprites;
 
-namespace SongBrowserPlugin.DataAccess
+namespace SongBrowser.DataAccess
 {
     public static class PlaylistsCollection
     {

+ 3 - 3
SongBrowserPlugin/DataAccess/ScoreSaberDatabase.cs

@@ -1,11 +1,11 @@
 using SimpleJSON;
-using SongBrowserPlugin.Logging;
+using SongBrowser.Logging;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin.DataAccess
+namespace SongBrowser.DataAccess
 {
     public class ScoreSaberDifficulty
     {

+ 2 - 2
SongBrowserPlugin/DataAccess/ScrappedData.cs

@@ -8,9 +8,9 @@ using System.Text;
 using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.Networking;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin.DataAccess
+namespace SongBrowser.DataAccess
 {
     public class ScrappedSong
     {

+ 28 - 24
SongBrowserPlugin/DataAccess/SongBrowserModel.cs

@@ -1,5 +1,5 @@
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.UI;
+using SongBrowser.DataAccess;
+using SongBrowser.UI;
 using SongLoaderPlugin;
 using SongLoaderPlugin.OverrideClasses;
 using System;
@@ -8,9 +8,9 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using UnityEngine;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin
+namespace SongBrowser
 {
     public class SongBrowserModel
     {
@@ -38,7 +38,7 @@ namespace SongBrowserPlugin
         public static Action<List<CustomLevel>> didFinishProcessingSongs;
 
         private IBeatmapLevelPack _currentLevelPack;
-        private Dictionary<string, List<BeatmapLevelSO>>  _levelPackToSongs;
+        private Dictionary<string, List<BeatmapLevelSO>> _levelPackToSongs;
 
         private bool _isPreviewLevelPack;
 
@@ -314,7 +314,7 @@ namespace SongBrowserPlugin
                 CurrentEditingPlaylist = new Playlist
                 {
                     playlistTitle = "Song Browser Favorites",
-                    playlistAuthor = "SongBrowserPlugin",
+                    playlistAuthor = "SongBrowser",
                     fileLoc = this.Settings.currentEditingPlaylistFile,
                     image = Base64Sprites.PlaylistIconB64,
                     songs = new List<PlaylistSong>(),
@@ -330,11 +330,11 @@ namespace SongBrowserPlugin
                     continue;
                 }
 
-                CurrentEditingPlaylistLevelIds.Add(ps.level.levelID);                
+                CurrentEditingPlaylistLevelIds.Add(ps.level.levelID);
             }
 
             // Actually sort and filter
-            this.ProcessSongList();
+            //this.ProcessSongList();
 
             // Signal complete
             if (SongLoader.CustomLevels.Count > 0)
@@ -395,7 +395,6 @@ namespace SongBrowserPlugin
         {
             // Build a map of levelId to sum of all playcounts and sort.
             PlayerDataModelSO playerData = Resources.FindObjectsOfTypeAll<PlayerDataModelSO>().FirstOrDefault();
-            IEnumerable<BeatmapDifficulty> difficultyIterator = Enum.GetValues(typeof(BeatmapDifficulty)).Cast<BeatmapDifficulty>();
 
             foreach (KeyValuePair<string, List<BeatmapLevelSO>> entry in _levelPackToSongs)
             {
@@ -405,13 +404,18 @@ namespace SongBrowserPlugin
                     {
                         // Skip folders
                         int playCountSum = 0;
-                        foreach (BeatmapDifficulty difficulty in difficultyIterator)
+                        foreach (IDifficultyBeatmapSet set in level.difficultyBeatmapSets)
                         {
-                            PlayerLevelStatsData stats = playerData.currentLocalPlayer.GetPlayerLevelStatsData(level.levelID, difficulty, this.CurrentBeatmapCharacteristicSO);
-                            playCountSum += stats.playCount;
+                            foreach (IDifficultyBeatmap beatmap in set.difficultyBeatmaps)
+                            {
+                                PlayerLevelStatsData stats = playerData.currentLocalPlayer.GetPlayerLevelStatsData(level.levelID, beatmap.difficulty, set.beatmapCharacteristic);
+                                playCountSum += stats.playCount;
+                            }
                         }
                         _levelIdToPlayCount.Add(level.levelID, playCountSum);
                     }
+
+
                 }
             }
         }
@@ -442,7 +446,7 @@ namespace SongBrowserPlugin
                 }
 
                 ScoreSaberData scoreSaberData = null;
-                
+
                 // try to version match first
                 if (_levelIdToSongVersion.ContainsKey(level.levelID))
                 {
@@ -458,7 +462,7 @@ namespace SongBrowserPlugin
                     //Logger.Debug("{0} = {1}pp", level.songName, pp);
                     _levelIdToScoreSaberData.Add(level.levelID, scoreSaberData);
                 }
-            }            
+            }
         }
 
         /// <summary>
@@ -476,7 +480,7 @@ namespace SongBrowserPlugin
             {
                 songName = songInfo.songName,
                 levelId = songInfo.levelID,
-                key = _levelIdToSongVersion.ContainsKey(songInfo.levelID) ? _levelIdToSongVersion[songInfo.levelID] : songInfo.levelID,                
+                key = _levelIdToSongVersion.ContainsKey(songInfo.levelID) ? _levelIdToSongVersion[songInfo.levelID] : songInfo.levelID,
             });
 
             this.CurrentEditingPlaylistLevelIds.Add(songInfo.levelID);
@@ -560,7 +564,7 @@ namespace SongBrowserPlugin
             var levels = _sortedSongs.ToArray();
             ReflectionUtil.SetPrivateField(levelPack.beatmapLevelCollection, "_beatmapLevels", levels);
         }
-        
+
         /// <summary>
         /// Sort the song list based on the settings.
         /// </summary>
@@ -680,8 +684,8 @@ namespace SongBrowserPlugin
 
             this.OverwriteCurrentLevelPack();
             //_sortedSongs.ForEach(x => Logger.Debug(x.levelID));
-        }    
-        
+        }
+
         /// <summary>
         /// For now the editing playlist will be considered the favorites playlist.
         /// Users can edit the settings file themselves.
@@ -742,7 +746,7 @@ namespace SongBrowserPlugin
             // Get song keys
             PlaylistsCollection.MatchSongsForPlaylist(this.CurrentPlaylist, true);
 
-            Logger.Debug("Filtering songs for playlist: {0}", this.CurrentPlaylist.playlistTitle);            
+            Logger.Debug("Filtering songs for playlist: {0}", this.CurrentPlaylist.playlistTitle);
 
             Dictionary<String, BeatmapLevelSO> levelDict = new Dictionary<string, BeatmapLevelSO>();
             foreach (KeyValuePair<string, List<BeatmapLevelSO>> entry in _levelPackToSongs)
@@ -768,7 +772,7 @@ namespace SongBrowserPlugin
                     Logger.Warning("Could not find song in playlist: {0}", ps.songName);
                 }
             }
-            
+
             Logger.Debug("Playlist filtered song count: {0}", songList.Count);
             return songList;
         }
@@ -820,7 +824,7 @@ namespace SongBrowserPlugin
             Logger.Info("Sorting song list by difficulty...");
 
             IEnumerable<BeatmapDifficulty> difficultyIterator = Enum.GetValues(typeof(BeatmapDifficulty)).Cast<BeatmapDifficulty>();
-            Dictionary<string, int>  levelIdToDifficultyValue = new Dictionary<string, int>();
+            Dictionary<string, int> levelIdToDifficultyValue = new Dictionary<string, int>();
             foreach (var level in levels)
             {
                 if (!levelIdToDifficultyValue.ContainsKey(level.levelID))
@@ -833,10 +837,10 @@ namespace SongBrowserPlugin
                         .SelectMany(x => x.difficultyBeatmaps);
 
                     foreach (IDifficultyBeatmap difficultyBeatmap in difficulties)
-                    {                            
+                    {
                         difficultyValue += _difficultyWeights[difficultyBeatmap.difficulty];
                     }
-                    levelIdToDifficultyValue.Add(level.levelID, difficultyValue);                    
+                    levelIdToDifficultyValue.Add(level.levelID, difficultyValue);
                 }
             }
 
@@ -856,7 +860,7 @@ namespace SongBrowserPlugin
             _sortedSongs = levels
                 .OrderBy(x => rnd.Next())
                 .ToList();
-        }        
+        }
 
         private void SortSongName(List<BeatmapLevelSO> levels)
         {

+ 6 - 6
SongBrowserPlugin/DataAccess/SongBrowserSettings.cs

@@ -1,14 +1,14 @@
-using SongBrowserPlugin.UI;
+using SongBrowser.UI;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
 using System.Xml;
 using System.Xml.Serialization;
-using SongBrowserPlugin.Logging;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using SongBrowser.Logging;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin.DataAccess
+namespace SongBrowser.DataAccess
 {
     [Serializable]
     public enum SongSortMode
@@ -175,7 +175,7 @@ namespace SongBrowserPlugin.DataAccess
                 Playlist p = new Playlist
                 {
                     playlistTitle = "Song Browser Favorites",
-                    playlistAuthor = "SongBrowserPlugin",
+                    playlistAuthor = "SongBrowser",
                     fileLoc = "",
                     image = Base64Sprites.PlaylistIconB64,
                     songs = new List<PlaylistSong>(),
@@ -236,7 +236,7 @@ namespace SongBrowserPlugin.DataAccess
                 p = new Playlist
                 {
                     playlistTitle = "Song Browser Favorites",
-                    playlistAuthor = "SongBrowserPlugin",
+                    playlistAuthor = "SongBrowser",
                     fileLoc = "",
                     image = Base64Sprites.PlaylistIconB64,
                     songs = new List<PlaylistSong>(),

+ 1 - 1
SongBrowserPlugin/Internals/BSEvents.cs

@@ -8,7 +8,7 @@ using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.SceneManagement;
 
-namespace SongBrowserPlugin.Internals
+namespace SongBrowser.Internals
 {
     class BSEvents : MonoBehaviour
     {

+ 4 - 3
SongBrowserPlugin/Internals/CustomHelpers.cs

@@ -8,9 +8,9 @@ using System.Text;
 using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.UI;
-using Sprites = SongBrowserPlugin.UI.Base64Sprites;
+using Sprites = SongBrowser.UI.Base64Sprites;
 
-namespace SongBrowserPlugin.Internals
+namespace SongBrowser.Internals
 {
     public static class CustomHelpers
     {
@@ -28,7 +28,7 @@ namespace SongBrowserPlugin.Internals
                 tableView.SelectCellWithIdx(rows.First(), callbackTable);
         }
 
-        public static IBeatmapLevelPack GetLevelPackWithLevels(BeatmapLevelSO[] levels, string packName = null, Sprite packCover = null)
+        public static BeatmapLevelPackSO GetLevelPackWithLevels(BeatmapLevelSO[] levels, string packName = null, Sprite packCover = null, string packID = null)
         {
             CustomLevelCollectionSO levelCollection = ScriptableObject.CreateInstance<CustomLevelCollectionSO>();
             levelCollection.SetPrivateField("_levelList", levels.ToList());
@@ -37,6 +37,7 @@ namespace SongBrowserPlugin.Internals
             CustomBeatmapLevelPackSO pack = CustomBeatmapLevelPackSO.GetPack(levelCollection);
             pack.SetPrivateField("_packName", string.IsNullOrEmpty(packName) ? "Custom Songs" : packName);
             pack.SetPrivateField("_coverImage", packCover ?? Sprites.BeastSaberLogo);
+            pack.SetPrivateField("_packID", string.IsNullOrEmpty(packID) ? "" : packID);
             pack.SetPrivateField("_isPackAlwaysOwned", true);
 
             return pack;

+ 2 - 2
SongBrowserPlugin/Logging/Logger.cs

@@ -1,6 +1,6 @@
 using System;
 
-namespace SongBrowserPlugin.Logging
+namespace SongBrowser.Logging
 {
     public enum LogLevel
     {
@@ -13,7 +13,7 @@ namespace SongBrowserPlugin.Logging
 
     public class Logger
     {
-        private static readonly string LoggerName = "SongBrowserPlugin";
+        private static readonly string LoggerName = "SongBrowser";
         private static readonly LogLevel LogLevel = LogLevel.Info;
         private static readonly ConsoleColor DefaultFgColor = ConsoleColor.Gray;
 

+ 6 - 6
SongBrowserPlugin/Plugin.cs

@@ -1,20 +1,20 @@
 using UnityEngine.SceneManagement;
 using IllusionPlugin;
 using UnityEngine;
-using SongBrowserPlugin.UI;
-using Logger = SongBrowserPlugin.Logging.Logger;
-using SongBrowserPlugin.DataAccess;
+using SongBrowser.UI;
+using Logger = SongBrowser.Logging.Logger;
+using SongBrowser.DataAccess;
 using System.Collections.Generic;
-using SongBrowserPlugin.Internals;
+using SongBrowser.Internals;
 using System;
 using SongLoaderPlugin;
 using SongLoaderPlugin.OverrideClasses;
 
-namespace SongBrowserPlugin
+namespace SongBrowser
 {
     public class Plugin : IPlugin
     {
-        public const string VERSION_NUMBER = "3.0.4";
+        public const string VERSION_NUMBER = "3.0.5";
 
         public string Name
         {

+ 3 - 3
SongBrowserPlugin/PluginConfig.cs

@@ -6,12 +6,12 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Xml.Serialization;
-using SongBrowserPlugin;
+using SongBrowser;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Converters;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin
+namespace SongBrowser
 {
     // Downloader config
     class PluginConfig

+ 4 - 4
SongBrowserPlugin/Properties/AssemblyInfo.cs

@@ -4,11 +4,11 @@ using System.Runtime.InteropServices;
 // General Information about an assembly is controlled through the following 
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
-[assembly: AssemblyTitle("SongBrowserPlugin")]
+[assembly: AssemblyTitle("SongBrowser")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("SongBrowserPlugin")]
+[assembly: AssemblyProduct("SongBrowser")]
 [assembly: AssemblyCopyright("Copyright ©  2019")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("3.0.4")]
-[assembly: AssemblyFileVersion("3.0.4")]
+[assembly: AssemblyVersion("3.0.5")]
+[assembly: AssemblyFileVersion("3.0.5")]

+ 33 - 23
SongBrowserPlugin/SongBrowserPlugin.csproj

@@ -7,9 +7,9 @@
     <ProjectGuid>{6F9B6801-9F4B-4D1F-805D-271C95733814}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>SongBrowserPlugin</RootNamespace>
-    <AssemblyName>SongBrowserPlugin</AssemblyName>
-    <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
+    <RootNamespace>SongBrowser</RootNamespace>
+    <AssemblyName>SongBrowser</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <LangVersion>6</LangVersion>
     <TargetFrameworkProfile>
@@ -38,27 +38,34 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="Assembly-CSharp">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\Assembly-CSharp.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\Assembly-CSharp.dll</HintPath>
     </Reference>
     <Reference Include="Assembly-CSharp-firstpass, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\Assembly-CSharp-firstpass.dll</HintPath>
     </Reference>
     <Reference Include="BeatSaberCustomUI">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Plugins\BeatSaberCustomUI.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Plugins\BeatSaberCustomUI.dll</HintPath>
+    </Reference>
+    <Reference Include="BS_Utils, Version=1.2.3.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Plugins\BS_Utils.dll</HintPath>
     </Reference>
     <Reference Include="IllusionPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\IllusionPlugin.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\IllusionPlugin.dll</HintPath>
     </Reference>
     <Reference Include="Newtonsoft.Json">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\Newtonsoft.Json.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="Polyglot.Scripts">
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\Polyglot.Scripts.dll</HintPath>
     </Reference>
     <Reference Include="ProBuilderCore">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\ProBuilderCore.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\ProBuilderCore.dll</HintPath>
     </Reference>
     <Reference Include="SongLoaderPlugin, Version=5.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Plugins\SongLoaderPlugin.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Plugins\SongLoaderPlugin.dll</HintPath>
     </Reference>
     <Reference Include="System" />
     <Reference Include="System.Data" />
@@ -67,51 +74,51 @@
     <Reference Include="System.Security" />
     <Reference Include="System.Xml" />
     <Reference Include="Unity.TextMeshPro">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\Unity.TextMeshPro.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\Unity.TextMeshPro.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.AudioModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.AudioModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.CoreModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.ImageConversionModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.ImageConversionModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.JSONSerializeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.JSONSerializeModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.Networking">
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.Networking.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.Networking.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UI.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UI.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.UIElementsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UIElementsModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UIModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UIModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.UnityWebRequestModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UnityWebRequestModule.dll</HintPath>
     </Reference>
     <Reference Include="UnityEngine.UnityWebRequestWWWModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
-      <HintPath>D:\Games\Steam\SteamApps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
+      <HintPath>C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll</HintPath>
     </Reference>
   </ItemGroup>
   <ItemGroup>
@@ -173,6 +180,9 @@
   </ItemGroup>
   <ItemGroup />
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <PropertyGroup>
+    <PostBuildEvent>xcopy "$(TargetDir)$(TargetFileName)" "C:\Program Files (x86)\Steam\steamapps\common\Beat Saber\Plugins" /Y</PostBuildEvent>
+  </PropertyGroup>
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
          Other similar extension points exist, see Microsoft.Common.targets.
     <Target Name="BeforeBuild">

+ 1 - 1
SongBrowserPlugin/SongBrowserPlugin.sln

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
 VisualStudioVersion = 15.0.27703.2026
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SongBrowserPlugin", "SongBrowserPlugin.csproj", "{6F9B6801-9F4B-4D1F-805D-271C95733814}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SongBrowser", "SongBrowser.csproj", "{6F9B6801-9F4B-4D1F-805D-271C95733814}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+ 6 - 6
SongBrowserPlugin/SongBrowserApplication.cs

@@ -1,5 +1,5 @@
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.UI;
+using SongBrowser.DataAccess;
+using SongBrowser.UI;
 using SongLoaderPlugin;
 using SongLoaderPlugin.OverrideClasses;
 using System;
@@ -8,9 +8,9 @@ using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 using UnityEngine.UI;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin
+namespace SongBrowser
 {
     public class SongBrowserApplication : MonoBehaviour
     {
@@ -22,7 +22,7 @@ namespace SongBrowserPlugin
 
         public Dictionary<String, Sprite> CachedIcons;
 
-        public static SongBrowserPlugin.UI.ProgressBar MainProgressBar;
+        public static SongBrowser.UI.ProgressBar MainProgressBar;
 
 
         /// <summary>
@@ -37,7 +37,7 @@ namespace SongBrowserPlugin
 
             new GameObject("Beat Saber SongBrowser Plugin").AddComponent<SongBrowserApplication>();
 
-            SongBrowserApplication.MainProgressBar = SongBrowserPlugin.UI.ProgressBar.Create();
+            SongBrowserApplication.MainProgressBar = SongBrowser.UI.ProgressBar.Create();
 
             Console.WriteLine("SongBrowser Plugin Loaded()");
         }

+ 1 - 1
SongBrowserPlugin/UI/BackButtonNavigationController.cs

@@ -7,7 +7,7 @@ using System.Threading.Tasks;
 using UnityEngine.UI;
 using VRUI;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     class BackButtonNavigationController : VRUINavigationController
     {

+ 3 - 3
SongBrowserPlugin/UI/Base64Sprites.cs

@@ -3,7 +3,7 @@ using System.Text.RegularExpressions;
 using UnityEngine;
 
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     class Base64Sprites
     {
@@ -61,12 +61,12 @@ namespace SongBrowserPlugin.UI
             SpeedIcon = Base64Sprites.Base64ToSprite(SpeedIconB64);
             StarIcon = Base64Sprites.Base64ToSprite(StarIconB64);
             GraphIcon = Base64Sprites.Base64ToSprite(GraphIconB64);
-            DeleteIcon = CustomUI.Utilities.UIUtilities.LoadSpriteFromResources("SongBrowserPlugin.Assets.DeleteIcon.png");
+            DeleteIcon = CustomUI.Utilities.UIUtilities.LoadSpriteFromResources("SongBrowser.Assets.DeleteIcon.png");
             XIcon = Base64Sprites.Base64ToSprite(XIconB64);
 
             SortButtonStroke = Base64Sprites.Base64ToSprite(SortButtonStrokeB64);
 
-            BeastSaberLogo = CustomUI.Utilities.UIUtilities.LoadSpriteFromResources("SongBrowserPlugin.Assets.BeastSaberLogo.png");            
+            BeastSaberLogo = CustomUI.Utilities.UIUtilities.LoadSpriteFromResources("SongBrowser.Assets.BeastSaberLogo.png");            
         }
 
         public static string SpriteToBase64(Sprite input)

+ 82 - 67
SongBrowserPlugin/UI/Browser/SongBrowserUI.cs

@@ -6,17 +6,17 @@ using System.Globalization;
 using UnityEngine.UI;
 using HMUI;
 using VRUI;
-using SongBrowserPlugin.DataAccess;
+using SongBrowser.DataAccess;
 using System.IO;
 using SongLoaderPlugin;
 using System.Security.Cryptography;
 using System.Text;
 using TMPro;
-using Logger = SongBrowserPlugin.Logging.Logger;
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
+using Logger = SongBrowser.Logging.Logger;
+using SongBrowser.DataAccess.BeatSaverApi;
 using System.Collections;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     /// <summary>
     /// Hijack the flow coordinator.  Have access to all StandardLevel easily.
@@ -46,7 +46,7 @@ namespace SongBrowserPlugin.UI
 
         private DismissableNavigationController _levelSelectionNavigationController;        
 
-        private RectTransform _tableViewRectTransform;
+        private RectTransform _levelPackLevelsTableViewRectTransform;
 
         private Button _tableViewPageUpButton;
         private Button _tableViewPageDownButton;
@@ -180,11 +180,12 @@ namespace SongBrowserPlugin.UI
                 _levelDifficultyViewController = _standardLevelDetailView.GetPrivateField<BeatmapDifficultySegmentedControlController>("_beatmapDifficultySegmentedControlController");
                 Logger.Debug("Acquired BeatmapDifficultySegmentedControlController [{0}]", _levelDifficultyViewController.GetInstanceID());
 
-                _tableViewRectTransform = _levelPackLevelsTableView.transform as RectTransform;
-                Logger.Debug("Acquired TableViewRectTransform from LevelPackLevelsTableView [{0}]", _tableViewRectTransform.GetInstanceID());
+                _levelPackLevelsTableViewRectTransform = _levelPackLevelsTableView.transform as RectTransform;
+                Logger.Debug("Acquired TableViewRectTransform from LevelPackLevelsTableView [{0}]", _levelPackLevelsTableViewRectTransform.GetInstanceID());
 
-                _tableViewPageUpButton = _tableViewRectTransform.GetComponentsInChildren<Button>().First(x => x.name == "PageUpButton");
-                _tableViewPageDownButton = _tableViewRectTransform.GetComponentsInChildren<Button>().First(x => x.name == "PageDownButton");
+                TableView tableView = ReflectionUtil.GetPrivateField<TableView>(_levelPackLevelsTableView, "_tableView");
+                _tableViewPageUpButton = tableView.GetPrivateField<Button>("_pageUpButton");
+                _tableViewPageDownButton = tableView.GetPrivateField<Button>("_pageDownButton");
                 Logger.Debug("Acquired Page Up and Down buttons...");
 
                 _playButton = _standardLevelDetailView.GetComponentsInChildren<Button>().FirstOrDefault(x => x.name == "PlayButton");
@@ -213,6 +214,7 @@ namespace SongBrowserPlugin.UI
                 this.InstallHandlers();
 
                 this.ResizeStatsPanel();
+                this.ResizeSongUI();
 
                 _uiCreated = true;
                 Logger.Debug("Done Creating UI...");
@@ -247,21 +249,17 @@ namespace SongBrowserPlugin.UI
                 Button playButton = Resources.FindObjectsOfTypeAll<Button>().First(x => x.name == "PlayButton");
                 RectTransform playButtonRect = (playButton.transform as RectTransform);
                 Sprite arrowIcon = SongBrowserApplication.Instance.CachedIcons["ArrowIcon"];
-                Sprite borderSprite = SongBrowserApplication.Instance.CachedIcons["RoundRectBigStroke"];
-
-                // Resize some of the UI
-                _tableViewRectTransform.sizeDelta = new Vector2(0f, -20f);
-                _tableViewRectTransform.anchoredPosition = new Vector2(0f, -2.5f);
+                Sprite borderSprite = SongBrowserApplication.Instance.CachedIcons["RoundRectBigStroke"];            
 
                 // Create Sorting Songs By-Buttons
                 Logger.Debug("Creating sort by buttons...");
                 float buttonSpacing = 0.5f;                                
                 float fontSize = 2.0f;
                 float buttonWidth = 12.25f;
-                float buttonHeight = 5.5f;
+                float buttonHeight = 5.0f;
                 float startButtonX = 24.50f;
                 float curButtonX = 0.0f;
-                float buttonY = -6.0f;
+                float buttonY = -5.25f;
                 Vector2 iconButtonSize = new Vector2(buttonHeight, buttonHeight);
 
                 // Create cancel button
@@ -270,7 +268,7 @@ namespace SongBrowserPlugin.UI
                     sortButtonTransform, 
                     otherButtonTemplate, 
                     Base64Sprites.XIcon, 
-                    new Vector2(startButtonX - buttonHeight - (buttonSpacing * 2.0f), buttonY), 
+                    new Vector2(startButtonX - buttonHeight, buttonY), 
                     new Vector2(iconButtonSize.x, iconButtonSize.y),
                     new Vector2(3.5f, 3.5f),
                     new Vector2(1.0f, 1.0f),
@@ -280,7 +278,7 @@ namespace SongBrowserPlugin.UI
                     OnClearButtonClickEvent();
                 });
 
-                startButtonX += (buttonHeight + buttonSpacing);
+                startButtonX += (buttonHeight * 2.0f);
 
                 // define sort buttons
                 string[] sortButtonNames = new string[]
@@ -343,7 +341,7 @@ namespace SongBrowserPlugin.UI
                     _filterButtonGroup.Add(filterButton);                    
                 }
 
-                // Create add favorite button
+                // Create add favorite button                
                 Logger.Debug("Creating Add to favorites button...");
                 _addFavoriteButton = UIBuilder.CreateIconButton(playButtonsRect,
                     practiceButton,
@@ -447,12 +445,32 @@ namespace SongBrowserPlugin.UI
             UIBuilder.SetStatButtonIcon(_njsStatButton, Base64Sprites.SpeedIcon);
 
             // shrink title
-            var titleText = this._levelDetailViewController.GetComponentsInChildren<TextMeshProUGUI>(true).First(x => x.name == "SongNameText");
-            
+            var titleText = this._levelDetailViewController.GetComponentsInChildren<TextMeshProUGUI>(true).First(x => x.name == "SongNameText");            
             titleText.fontSize = 5.0f;
         }
 
         /// <summary>
+        /// Resize some of the song table elements.
+        /// </summary>
+        public void ResizeSongUI()
+        {
+            // Reposition the table view a bit
+            _levelPackLevelsTableViewRectTransform.anchoredPosition = new Vector2(0f, -2.5f);
+
+            // Move the page up/down buttons a bit
+            TableView tableView = ReflectionUtil.GetPrivateField<TableView>(_levelPackLevelsTableView, "_tableView");
+            RectTransform pageUpButton = _tableViewPageUpButton.transform as RectTransform;
+            RectTransform pageDownButton = _tableViewPageDownButton.transform as RectTransform;
+            pageUpButton.anchoredPosition = new Vector2(pageUpButton.anchoredPosition.x, pageUpButton.anchoredPosition.y - 1f);
+            pageDownButton.anchoredPosition = new Vector2(pageDownButton.anchoredPosition.x, pageDownButton.anchoredPosition.y + 1f);
+
+            // shrink play button container
+            RectTransform playContainerRect = _standardLevelDetailView.GetComponentsInChildren<RectTransform>().First(x => x.name == "PlayContainer");
+            RectTransform playButtonsRect = playContainerRect.GetComponentsInChildren<RectTransform>().First(x => x.name == "PlayButtons");
+            playButtonsRect.localScale = new Vector3(0.95f, 0.95f, 0.95f);
+        }
+
+        /// <summary>
         /// Show the UI.
         /// </summary>
         public void Show()
@@ -574,14 +592,7 @@ namespace SongBrowserPlugin.UI
 
             try
             {
-                // reset filter mode always here
-                this._model.Settings.filterMode = SongFilterMode.None;
-                this._model.Settings.Save();
-
-                this._model.SetCurrentLevelPack(arg2);
-                this._model.ProcessSongList();
-
-                RefreshSongList();
+                //RefreshSongList();
                 RefreshSortButtonUI();
                 RefreshQuickScrollButtons();
             }
@@ -603,6 +614,16 @@ namespace SongBrowserPlugin.UI
 
             try
             {
+                // reset filter mode always here
+                if (this._model.Settings.currentLevelPackId != arg2.packID)// this._model.Settings.filterMode == SongFilterMode.Playlist)
+                {
+                    this._model.Settings.filterMode = SongFilterMode.None;
+                    this._model.Settings.Save();
+                }                
+
+                this._model.SetCurrentLevelPack(arg2);
+                this._model.ProcessSongList();
+
                 RefreshSongList();
                 RefreshSortButtonUI();
                 RefreshQuickScrollButtons();
@@ -613,6 +634,9 @@ namespace SongBrowserPlugin.UI
             }
         }
 
+        /// <summary>
+        /// Remove all filters, update song list, save.
+        /// </summary>
         private void OnClearButtonClickEvent()
         {
             Logger.Debug("Clearing all sorts and filters.");
@@ -1145,48 +1169,26 @@ namespace SongBrowserPlugin.UI
         /// Update interactive state of the quick scroll buttons.
         /// </summary>
         private void RefreshQuickScrollButtons()
-        {
-            // if you are ever viewing the song list with less than 5 songs the up/down buttons do not exist.
-            // just try and fetch them and ignore the exception.
-            if (_tableViewPageUpButton == null)
-            {
-                try
-                {
-                    _tableViewPageUpButton = _tableViewRectTransform.GetComponentsInChildren<Button>().First(x => x.name == "PageUpButton");
-                    (_tableViewPageUpButton.transform as RectTransform).anchoredPosition = new Vector2(0f, -1f);
-                }
-                catch (Exception)
-                {
-                    // We don't care if this fails.
-                    return;
-                }
-            }
-
-            if (_tableViewPageDownButton == null)
-            {
-                try
-                {
-                    _tableViewPageDownButton = _tableViewRectTransform.GetComponentsInChildren<Button>().First(x => x.name == "PageDownButton");
-                    (_tableViewPageDownButton.transform as RectTransform).anchoredPosition = new Vector2(0f, 1f);
-                }
-                catch (Exception)
-                {
-                    // We don't care if this fails.
-                    return;
-                }
-            }
-
+        {         
             // Refresh the fast scroll buttons
             if (_tableViewPageUpButton != null && _pageUpFastButton != null)
             {
                 _pageUpFastButton.interactable = _tableViewPageUpButton.interactable;
                 _pageUpFastButton.gameObject.SetActive(_tableViewPageUpButton.IsActive());
             }
+            else
+            {
+                _pageUpFastButton.gameObject.SetActive(false);
+            }
 
-            if (_tableViewPageDownButton != null && _pageUpFastButton != null)
+            if (_tableViewPageDownButton != null && _pageDownFastButton != null)
             {
                 _pageDownFastButton.interactable = _tableViewPageDownButton.interactable;
-                _pageDownFastButton.gameObject.SetActive(_tableViewPageDownButton.IsActive());
+                _pageDownFastButton.gameObject.SetActive(_tableViewPageDownButton.IsActive());                
+            }
+            else
+            {
+                _pageDownFastButton.gameObject.SetActive(false);
             }
         }
 
@@ -1461,7 +1463,7 @@ namespace SongBrowserPlugin.UI
                 // this might look like an off by one error but the _level list we keep is missing the header entry BeatSaber.
                 // so the last row is +1 the max index, the count.
                 int maxCount = _model.SortedSongList.Count;
-                Logger.Debug("Song is not in the level pack, cannot scroll to it...  Using last known row");
+                Logger.Debug("Song is not in the level pack, cannot scroll to it...  Using last known row {0}/{1}", _lastRow, maxCount);
                 selectedIndex = Math.Min(maxCount, _lastRow);
             }
             else
@@ -1510,7 +1512,11 @@ namespace SongBrowserPlugin.UI
 
                 _model.UpdateLevelRecords();
 
-                UpdateLevelPackSelection();
+                bool didUpdateLevelPack = UpdateLevelPackSelection();
+                if (!didUpdateLevelPack)
+                {
+                    _model.ProcessSongList();
+                }
             }
             catch (Exception e)
             {
@@ -1528,8 +1534,9 @@ namespace SongBrowserPlugin.UI
 
         /// <summary>
         /// Logic for fixing BeatSaber's level pack selection bugs.
+        /// 
         /// </summary>
-        public void UpdateLevelPackSelection()
+        public bool UpdateLevelPackSelection()
         {
             if (_levelPackViewController != null)
             {
@@ -1546,7 +1553,7 @@ namespace SongBrowserPlugin.UI
                     }
                     this._model.SetCurrentLevelPack(currentSelected);
                 }
-                else if (currentSelected == null || (currentSelected.packID != _model.Settings.currentLevelId))
+                else if (currentSelected == null || (currentSelected.packID != _model.Settings.currentLevelPackId))
                 {
                     Logger.Debug("Automatically selecting level pack: {0}", _model.Settings.currentLevelPackId);
 
@@ -1561,10 +1568,18 @@ namespace SongBrowserPlugin.UI
                     this._model.SetCurrentLevelPack(levelPack);
                     this._model.ProcessSongList();
 
-                    _levelPacksTableView.didSelectPackEvent += _levelPacksTableView_didSelectPackEvent;
                     _levelPackViewController.didSelectPackEvent += _levelPackViewController_didSelectPackEvent;
+                    _levelPacksTableView.didSelectPackEvent += _levelPacksTableView_didSelectPackEvent;
+                    
+                    return true;
+                }
+                else
+                {
+                    this._model.SetCurrentLevelPack(currentSelected);
                 }
             }
+
+            return false;
         }
 
         //Pull njs from a difficulty, based on private function from SongLoader

+ 2 - 2
SongBrowserPlugin/UI/Browser/SongFilterButton.cs

@@ -1,7 +1,7 @@
-using SongBrowserPlugin.DataAccess;
+using SongBrowser.DataAccess;
 using UnityEngine.UI;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     class SongFilterButton
     {

+ 2 - 2
SongBrowserPlugin/UI/Browser/SongSortButton.cs

@@ -1,7 +1,7 @@
-using SongBrowserPlugin.DataAccess;
+using SongBrowser.DataAccess;
 using UnityEngine.UI;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     public class SongSortButton
     {

+ 3 - 3
SongBrowserPlugin/UI/DownloadQueue/DownloadQueueTableCell.cs

@@ -1,12 +1,12 @@
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
+using SongBrowser.DataAccess;
+using SongBrowser.DataAccess.BeatSaverApi;
 using System.Linq;
 using System.Reflection;
 using TMPro;
 using UnityEngine;
 
 // From: https://github.com/andruzzzhka/BeatSaverDownloader
-namespace SongBrowserPlugin.UI.DownloadQueue
+namespace SongBrowser.UI.DownloadQueue
 {
     class DownloadQueueTableCell : LevelListTableCell
     {

+ 3 - 3
SongBrowserPlugin/UI/DownloadQueue/DownloadQueueViewController.cs

@@ -1,7 +1,7 @@
 using CustomUI.BeatSaber;
 using CustomUI.Utilities;
 using HMUI;
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
+using SongBrowser.DataAccess.BeatSaverApi;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -10,11 +10,11 @@ using TMPro;
 using UnityEngine;
 using UnityEngine.UI;
 using VRUI;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
 // Modified From: https://github.com/andruzzzhka/BeatSaverDownloader
 // - Adding queue count
-namespace SongBrowserPlugin.UI.DownloadQueue
+namespace SongBrowser.UI.DownloadQueue
 {
     class DownloadQueueViewController : VRUIViewController, TableView.IDataSource
     {

+ 2 - 2
SongBrowserPlugin/UI/Keyboard/CustomUIKeyboard.cs

@@ -4,9 +4,9 @@ using System.Linq;
 using System.Text;
 using UnityEngine;
 using UnityEngine.UI;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     // https://github.com/andruzzzhka/BeatSaverDownloader/blob/master/BeatSaverDownloader/PluginUI/UIElements/CustomUIKeyboard.cs
     class CustomUIKeyboard : MonoBehaviour

+ 1 - 1
SongBrowserPlugin/UI/Keyboard/SearchKeyboardViewController.cs

@@ -7,7 +7,7 @@ using UnityEngine;
 using UnityEngine.UI;
 using VRUI;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     // https://github.com/andruzzzhka/BeatSaverDownloader/blob/master/BeatSaverDownloader/PluginUI/ViewControllers/SearchKeyboardViewController.cs
     class SearchKeyboardViewController : VRUIViewController

+ 7 - 4
SongBrowserPlugin/UI/Playlists/PlaylistDetailViewController.cs

@@ -1,5 +1,5 @@
 using CustomUI.BeatSaber;
-using SongBrowserPlugin.DataAccess;
+using SongBrowser.DataAccess;
 using SongLoaderPlugin;
 using System;
 using System.Linq;
@@ -7,10 +7,10 @@ using TMPro;
 using UnityEngine;
 using UnityEngine.UI;
 using VRUI;
-using Logger = SongBrowserPlugin.Logging.Logger;
-using Sprites = SongBrowserPlugin.UI.Base64Sprites;
+using Logger = SongBrowser.Logging.Logger;
+using Sprites = SongBrowser.UI.Base64Sprites;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     class PlaylistDetailViewController : VRUIViewController
     {
@@ -40,6 +40,8 @@ namespace SongBrowserPlugin.UI
             if (firstActivation && type == ActivationType.AddedToHierarchy)
             {
                 gameObject.SetActive(true);
+                rectTransform.sizeDelta = new Vector2(60f, 0f);
+
                 _levelDetails = GetComponentsInChildren<StandardLevelDetailView>(true).First(x => x.name == "LevelDetail");
                 _levelDetails.gameObject.SetActive(true);
 
@@ -59,6 +61,7 @@ namespace SongBrowserPlugin.UI
                 {
                     songNameText = _textComponents.First(x => x.name == "SongNameText");
                     _textComponents.First(x => x.name == "Title").text = "Playlist";
+                    songNameText.enableWordWrapping = true;
 
                     _textComponents.First(x => x.name == "Title" && x.transform.parent.name == "MaxCombo").text = "Author";
                     authorText = _textComponents.First(x => x.name == "Value" && x.transform.parent.name == "MaxCombo");

+ 6 - 6
SongBrowserPlugin/UI/Playlists/PlaylistFlowCoordinator.cs

@@ -1,9 +1,9 @@
 using CustomUI.BeatSaber;
 using SimpleJSON;
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
-using SongBrowserPlugin.Internals;
-using SongBrowserPlugin.UI.DownloadQueue;
+using SongBrowser.DataAccess;
+using SongBrowser.DataAccess.BeatSaverApi;
+using SongBrowser.Internals;
+using SongBrowser.UI.DownloadQueue;
 using SongLoaderPlugin;
 using System;
 using System.Collections;
@@ -14,9 +14,9 @@ using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.Networking;
 using VRUI;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     // https://github.com/andruzzzhka/BeatSaverDownloader/blob/master/BeatSaverDownloader/UI/FlowCoordinators/PlaylistsFlowCoordinator.cs
     // +Keyboard Input

+ 15 - 12
SongBrowserPlugin/UI/Playlists/PlaylistSelectionListViewController.cs

@@ -1,6 +1,6 @@
 using HMUI;
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.Internals;
+using SongBrowser.DataAccess;
+using SongBrowser.Internals;
 using SongLoaderPlugin;
 using System;
 using System.Collections.Generic;
@@ -11,7 +11,7 @@ using UnityEngine;
 using UnityEngine.UI;
 using VRUI;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     class PlaylistListViewController : VRUIViewController, TableView.IDataSource
     {
@@ -31,19 +31,17 @@ namespace SongBrowserPlugin.UI
 
         protected override void DidActivate(bool firstActivation, ActivationType type)
         {
-
-
             if (firstActivation && type == ActivationType.AddedToHierarchy)
             {
                 rectTransform.anchorMin = new Vector2(0.5f, 0f);
                 rectTransform.anchorMax = new Vector2(0.5f, 1f);
-                rectTransform.sizeDelta = new Vector2(74f, 0f);
-                rectTransform.pivot = new Vector2(0.4f, 0.5f);
+                rectTransform.sizeDelta = new Vector2(75f, 0f);
+                rectTransform.pivot = new Vector2(0.5f, 0.5f);
 
                 _pageUpButton = Instantiate(Resources.FindObjectsOfTypeAll<Button>().Last(x => (x.name == "PageUpButton")), rectTransform, false);
                 (_pageUpButton.transform as RectTransform).anchorMin = new Vector2(0.5f, 1f);
                 (_pageUpButton.transform as RectTransform).anchorMax = new Vector2(0.5f, 1f);
-                (_pageUpButton.transform as RectTransform).anchoredPosition = new Vector2(0f, -10f);
+                (_pageUpButton.transform as RectTransform).anchoredPosition = new Vector2(0f, -9f);
                 (_pageUpButton.transform as RectTransform).sizeDelta = new Vector2(40f, 10f);
                 _pageUpButton.interactable = true;
                 _pageUpButton.onClick.AddListener(delegate ()
@@ -51,10 +49,10 @@ namespace SongBrowserPlugin.UI
                     _songsTableView.PageScrollUp();
                 });
 
-                _pageDownButton = Instantiate(Resources.FindObjectsOfTypeAll<Button>().Last(x => (x.name == "PageDownButton")), rectTransform, false);
+                _pageDownButton = Instantiate(Resources.FindObjectsOfTypeAll<Button>().First(x => (x.name == "PageDownButton")), rectTransform, false);
                 (_pageDownButton.transform as RectTransform).anchorMin = new Vector2(0.5f, 0f);
                 (_pageDownButton.transform as RectTransform).anchorMax = new Vector2(0.5f, 0f);
-                (_pageDownButton.transform as RectTransform).anchoredPosition = new Vector2(0f, 10f);
+                (_pageDownButton.transform as RectTransform).anchoredPosition = new Vector2(0f, 9f);
                 (_pageDownButton.transform as RectTransform).sizeDelta = new Vector2(40f, 10f);
                 _pageDownButton.interactable = true;
                 _pageDownButton.onClick.AddListener(delegate ()
@@ -66,7 +64,10 @@ namespace SongBrowserPlugin.UI
 
                 RectTransform container = new GameObject("CustomListContainer", typeof(RectTransform)).transform as RectTransform;
                 container.SetParent(rectTransform, false);
-                container.sizeDelta = new Vector2(60f, 0f);
+                container.anchorMin = new Vector2(0f, 0.5f);
+                container.anchorMax = new Vector2(1f, 0.5f);
+                container.sizeDelta = new Vector2(0f, 0f);
+                container.anchoredPosition = new Vector2(0f, 0f);
 
                 _songsTableView = new GameObject("CustomTableView", typeof(RectTransform)).AddComponent<TableView>();
                 _songsTableView.gameObject.AddComponent<RectMask2D>();
@@ -139,7 +140,9 @@ namespace SongBrowserPlugin.UI
             LevelListTableCell _tableCell = Instantiate(_songListTableCellInstance);
 
             _tableCell.reuseIdentifier = "PlaylistTableCell";
-            _tableCell.GetPrivateField<TextMeshProUGUI>("_songNameText").text = playlistList[row].playlistTitle;
+            var songNameText = _tableCell.GetPrivateField<TextMeshProUGUI>("_songNameText");
+            songNameText.text = playlistList[row].playlistTitle;
+            songNameText.overflowMode = TextOverflowModes.Overflow;
             _tableCell.GetPrivateField<TextMeshProUGUI>("_authorText").text = playlistList[row].playlistAuthor;
             _tableCell.GetPrivateField<UnityEngine.UI.Image>("_coverImage").sprite = playlistList[row].icon;
 

+ 1 - 1
SongBrowserPlugin/UI/ProgressBar.cs

@@ -11,7 +11,7 @@ using TMPro;
 using UnityEngine;
 using UnityEngine.SceneManagement;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     // Modified version of:
     // https://raw.githubusercontent.com/xyonico/BeatSaberSongLoader/master/SongLoaderPlugin/ProgressBar.cs

+ 1 - 1
SongBrowserPlugin/UI/SceneEvents.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.SceneManagement;
 
-namespace SongBrowserPlugin
+namespace SongBrowser
 {
     public class SceneEvents : MonoBehaviour
     {

+ 4 - 4
SongBrowserPlugin/UI/ScoreSaberDatabaseDownloader.cs

@@ -1,13 +1,13 @@
 using Mobcast.Coffee.AssetSystem;
-using SongBrowserPlugin.DataAccess;
-using SongBrowserPlugin.DataAccess.Network;
+using SongBrowser.DataAccess;
+using SongBrowser.DataAccess.Network;
 using System;
 using System.Collections;
 using UnityEngine;
 using UnityEngine.Networking;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     public class ScoreSaberDatabaseDownloader : MonoBehaviour
     {

+ 9 - 3
SongBrowserPlugin/UI/UIBuilder.cs

@@ -1,4 +1,4 @@
-using SongBrowserPlugin.DataAccess;
+using SongBrowser.DataAccess;
 using System;
 using System.Linq;
 using TMPro;
@@ -6,10 +6,10 @@ using UnityEngine;
 using UnityEngine.UI;
 using VRUI;
 using Image = UnityEngine.UI.Image;
-using Logger = SongBrowserPlugin.Logging.Logger;
+using Logger = SongBrowser.Logging.Logger;
 
 
-namespace SongBrowserPlugin.UI
+namespace SongBrowser.UI
 {
     public static class UIBuilder
     {
@@ -207,6 +207,12 @@ namespace SongBrowserPlugin.UI
         /// <param name="text"></param>
         static public void SetButtonText(Button button, string text)
         {
+            Polyglot.LocalizedTextMeshProUGUI localizer = button.GetComponentInChildren<Polyglot.LocalizedTextMeshProUGUI>();
+            if (localizer != null)
+            {
+                GameObject.Destroy(localizer);
+            }
+
             TextMeshProUGUI txt = button.GetComponentsInChildren<TextMeshProUGUI>().FirstOrDefault(x => x.name == "Text");
             if (txt != null)
             {