diff --git a/BSIPA-ModList/BSIPA-ModList.csproj b/BSIPA-ModList/BSIPA-ModList.csproj
index 77fb4b2e..126b0af5 100644
--- a/BSIPA-ModList/BSIPA-ModList.csproj
+++ b/BSIPA-ModList/BSIPA-ModList.csproj
@@ -97,6 +97,9 @@
+
+
+
diff --git a/BSIPA-ModList/Icons/Thumbs.db b/BSIPA-ModList/Icons/Thumbs.db
index 3f84cf47..f50e0834 100644
Binary files a/BSIPA-ModList/Icons/Thumbs.db and b/BSIPA-ModList/Icons/Thumbs.db differ
diff --git a/BSIPA-ModList/Icons/library.png b/BSIPA-ModList/Icons/library.png
new file mode 100644
index 00000000..1b9e0aa7
Binary files /dev/null and b/BSIPA-ModList/Icons/library.png differ
diff --git a/BSIPA-ModList/UI/ViewControllers/ModListController.cs b/BSIPA-ModList/UI/ViewControllers/ModListController.cs
index 48a056dd..91a19968 100644
--- a/BSIPA-ModList/UI/ViewControllers/ModListController.cs
+++ b/BSIPA-ModList/UI/ViewControllers/ModListController.cs
@@ -118,6 +118,56 @@ namespace BSIPA_ModList.UI
list.flow.SetSelected(infoView, immediate: list.flow.HasSelected);
}
}
+ private class LibraryModCell : CustomCellInfo, IClickableCell
+ {
+ private static Sprite _defaultIcon;
+ public static Sprite DefaultIcon
+ {
+ get
+ {
+ if (_defaultIcon == null)
+ _defaultIcon = UIUtilities.LoadSpriteFromResources("BSIPA_ModList.Icons.library.png");
+ return _defaultIcon;
+ }
+ }
+
+ internal PluginLoader.PluginInfo Plugin;
+ private ModListController list;
+
+ public LibraryModCell(ModListController list, PluginLoader.PluginInfo plugin)
+ : base($"{plugin.Metadata.Name} v{plugin.Metadata.Version}", plugin.Metadata.Manifest.Author, null)
+ {
+ Plugin = plugin;
+ this.list = list;
+
+ if (string.IsNullOrWhiteSpace(subtext))
+ subtext = "Unspecified Author";
+
+ icon = DefaultIcon;
+
+ Logger.log.Debug($"LibraryModCell {plugin.Metadata.Name} {plugin.Metadata.Version}");
+ }
+
+ private ModInfoViewController infoView;
+
+ public void OnSelect(ModListController cntrl)
+ {
+ Logger.log.Debug($"Selected LibraryModCell {Plugin.Metadata.Name} {Plugin.Metadata.Version}");
+
+ if (infoView == null)
+ {
+ var desc = Plugin.Metadata.Manifest.Description;
+ if (string.IsNullOrWhiteSpace(desc))
+ desc = "No description";
+
+ infoView = BeatSaberUI.CreateViewController();
+ infoView.Init(icon, Plugin.Metadata.Name, "v" + Plugin.Metadata.Version.ToString(), subtext,
+ desc, Plugin.Metadata.Features.FirstOrDefault(f => f is NoUpdateFeature) == null);
+ }
+
+ list.flow.SetSelected(infoView, immediate: list.flow.HasSelected);
+ }
+ }
#pragma warning disable CS0618
private class IPAModCell : CustomCellInfo, IClickableCell
@@ -190,10 +240,12 @@ namespace BSIPA_ModList.UI
reuseIdentifier = "BSIPAModListTableCell";
- foreach (var plugin in bsipaPlugins)
+ foreach (var plugin in bsipaPlugins.Where(p => !p.Metadata.IsBare))
Data.Add(new BSIPAModCell(this, plugin));
foreach (var plugin in ignoredPlugins)
Data.Add(new BSIPAIgnoredModCell(this, plugin));
+ foreach (var plugin in bsipaPlugins.Where(p => p.Metadata.IsBare))
+ Data.Add(new LibraryModCell(this, plugin));
foreach (var plugin in ipaPlugins)
Data.Add(new IPAModCell(this, plugin));
}
diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs
index a66ee4af..dd4756a4 100644
--- a/IPA.Loader/Loader/PluginLoader.cs
+++ b/IPA.Loader/Loader/PluginLoader.cs
@@ -71,6 +71,8 @@ namespace IPA.Loader
internal bool IsSelf;
+ internal bool IsBare;
+
private PluginManifest manifest;
internal HashSet Dependencies { get; } = new HashSet();
@@ -212,6 +214,31 @@ namespace IPA.Loader
Logger.loader.Error(e);
}
}
+
+ IEnumerable bareManifests = Directory.GetFiles(BeatSaber.PluginsPath, "*.json");
+ bareManifests = bareManifests.Concat(Directory.GetFiles(BeatSaber.PluginsPath, "*.manifest"));
+ foreach (var manifest in bareManifests)
+ {
+ try
+ {
+ var metadata = new PluginMetadata
+ {
+ File = new FileInfo(Path.Combine(BeatSaber.PluginsPath, manifest)),
+ IsSelf = false,
+ IsBare = true,
+ };
+
+ metadata.Manifest = JsonConvert.DeserializeObject(File.ReadAllText(manifest));
+
+ Logger.loader.Debug($"Adding info for bare manifest {Path.GetFileName(manifest)}");
+ PluginsMetadata.Add(metadata);
+ }
+ catch (Exception e)
+ {
+ Logger.loader.Error($"Could not load data for bare manifest {Path.GetFileName(manifest)}");
+ Logger.loader.Error(e);
+ }
+ }
}
// keep track of these for the updater; it should still be able to update mods not loaded
@@ -219,7 +246,7 @@ namespace IPA.Loader
internal static void Resolve()
{ // resolves duplicates and conflicts, etc
- PluginsMetadata.Sort((a, b) => a.Version.CompareTo(b.Version));
+ PluginsMetadata.Sort((a, b) => b.Version.CompareTo(a.Version));
var ids = new HashSet();
var ignore = new HashSet();
@@ -431,7 +458,7 @@ namespace IPA.Loader
internal static void Load(PluginMetadata meta)
{
- if (meta.Assembly == null)
+ if (meta.Assembly == null && meta.PluginType != null)
meta.Assembly = Assembly.LoadFrom(meta.File.FullName);
}
diff --git a/IPA.Loader/Loader/manifest.json b/IPA.Loader/Loader/manifest.json
index 3c55f6cb..b53f052b 100644
--- a/IPA.Loader/Loader/manifest.json
+++ b/IPA.Loader/Loader/manifest.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://raw.githubusercontent.com/nike4613/ModSaber-MetadataFileSchema/master/Schema.json",
+ "$schema": "https://raw.githubusercontent.com/beat-saber-modding-group/BSIPA-MetadataFileSchema/master/Schema.json",
"author": "DaNike",
"description": "A mod loader specifically for Beat Saber.",
"gameVersion": "0.13.2",
diff --git a/Refs/BeatSaberCustomUI.dll b/Refs/BeatSaberCustomUI.dll
index 297e4173..b22737ac 100644
Binary files a/Refs/BeatSaberCustomUI.dll and b/Refs/BeatSaberCustomUI.dll differ