diff --git a/IPA.Injector/Updates.cs b/IPA.Injector/Updates.cs
index aea8891c..663095c5 100644
--- a/IPA.Injector/Updates.cs
+++ b/IPA.Injector/Updates.cs
@@ -9,7 +9,7 @@ namespace IPA.Injector
{
internal static class Updates
{
- private const string DeleteFileName = Updating.ModSaber.Updater.SpecialDeletionsFile;
+ private const string DeleteFileName = Updating.BeatMods.Updater.SpecialDeletionsFile;
public static void InstallPendingUpdates()
{
var pendingDir = Path.Combine(BeatSaber.InstallPath, "IPA", "Pending");
diff --git a/IPA.Loader/Config/SelfConfig.cs b/IPA.Loader/Config/SelfConfig.cs
index b2e4328a..f15c5ec2 100644
--- a/IPA.Loader/Config/SelfConfig.cs
+++ b/IPA.Loader/Config/SelfConfig.cs
@@ -33,7 +33,7 @@ namespace IPA.Config
}
internal const string IPAName = "Beat Saber IPA";
- internal const string IPAVersion = "3.12.9";
+ internal const string IPAVersion = "3.12.10";
public bool Regenerate = true;
diff --git a/IPA.Loader/IPA.Loader.csproj b/IPA.Loader/IPA.Loader.csproj
index 73f38bb1..2613576f 100644
--- a/IPA.Loader/IPA.Loader.csproj
+++ b/IPA.Loader/IPA.Loader.csproj
@@ -89,7 +89,6 @@
-
@@ -105,8 +104,8 @@
-
-
+
+
diff --git a/IPA.Loader/JsonConverters/ModSaberDependencyConverter.cs b/IPA.Loader/JsonConverters/ModSaberDependencyConverter.cs
deleted file mode 100644
index 18cfa2e0..00000000
--- a/IPA.Loader/JsonConverters/ModSaberDependencyConverter.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-using IPA.Updating.ModSaber;
-using Newtonsoft.Json;
-using SemVer;
-
-namespace IPA.JsonConverters
-{
- internal class ModSaberDependencyConverter : JsonConverter
- {
- public override ApiEndpoint.Mod.Dependency ReadJson(JsonReader reader, Type objectType, ApiEndpoint.Mod.Dependency existingValue, bool hasExistingValue, JsonSerializer serializer)
- {
- var parts = (reader.Value as string)?.Split('@');
- return new ApiEndpoint.Mod.Dependency
- {
- Name = parts?[0],
- VersionRange = new Range(parts?[1])
- };
- }
-
- public override void WriteJson(JsonWriter writer, ApiEndpoint.Mod.Dependency value, JsonSerializer serializer)
- {
- writer.WriteValue($"{value.Name}@{value.VersionRange}");
- }
- }
-}
diff --git a/IPA.Loader/Loader/PluginComponent.cs b/IPA.Loader/Loader/PluginComponent.cs
index 5ab3c2cb..b2b4553c 100644
--- a/IPA.Loader/Loader/PluginComponent.cs
+++ b/IPA.Loader/Loader/PluginComponent.cs
@@ -28,7 +28,7 @@ namespace IPA.Loader
#pragma warning restore 618
/* kill this for now, until theres a new system */
- //gameObject.AddComponent();
+ gameObject.AddComponent();
bsPlugins.OnApplicationStart();
ipaPlugins.OnApplicationStart();
diff --git a/IPA.Loader/Loader/manifest.json b/IPA.Loader/Loader/manifest.json
index f2e855e3..985a963e 100644
--- a/IPA.Loader/Loader/manifest.json
+++ b/IPA.Loader/Loader/manifest.json
@@ -3,9 +3,9 @@
"author": "DaNike",
"description": "A mod loader specifically for Beat Saber.",
"gameVersion": "0.13.2",
- "id": "beatsaber-ipa-reloaded",
- "name": "BSIPA",
- "version": "3.12.9",
+ "id": "BSIPA",
+ "name": "Beat Saber IPA",
+ "version": "3.12.10",
"features": [
"define-feature(print, IPA.Loader.Features.PrintFeature)",
"define-feature(debug, IPA.Loader.Features.DebugFeature)",
diff --git a/IPA.Loader/Updating/ModSaber/ApiEndpoint.cs b/IPA.Loader/Updating/BeatMods/ApiEndpoint.cs
similarity index 65%
rename from IPA.Loader/Updating/ModSaber/ApiEndpoint.cs
rename to IPA.Loader/Updating/BeatMods/ApiEndpoint.cs
index 72d51825..d61c2f77 100644
--- a/IPA.Loader/Updating/ModSaber/ApiEndpoint.cs
+++ b/IPA.Loader/Updating/BeatMods/ApiEndpoint.cs
@@ -7,13 +7,14 @@ using Newtonsoft.Json;
using SemVer;
using Version = SemVer.Version;
-namespace IPA.Updating.ModSaber
+namespace IPA.Updating.BeatMods
{
class ApiEndpoint
{
- public const string ApiBase = "https://www.modsaber.org/";
- public const string GetModInfoEndpoint = "registry/{0}/{1}";
- public const string GetModsWithSemver = "api/v1.1/mods/semver/{0}/{1}";
+ public const string BeatModBase = "https://beatmods.com";
+ public const string ApiBase = BeatModBase + "/api/v1/mod";
+ public const string GetModInfoEndpoint = "?name={0}&version={1}";
+ public const string GetModsByName = "?name={0}";
class HexArrayConverter : JsonConverter
{
@@ -64,6 +65,15 @@ namespace IPA.Updating.ModSaber
public class Mod
{
#pragma warning disable CS0649
+ ///
+ /// Will be a useless string of characters. Do not use.
+ ///
+ [JsonProperty("_id")]
+ public string Id;
+
+ [JsonProperty("required")]
+ public bool Required;
+
[JsonProperty("name")]
public string Name;
@@ -74,15 +84,18 @@ namespace IPA.Updating.ModSaber
[Serializable]
public class AuthorType
{
- [JsonProperty("name")]
+ [JsonProperty("username")]
public string Name;
- [JsonProperty("id")]
+ [JsonProperty("_id")]
public string Id;
public override string ToString() => Name;
}
- [Serializable]
+ [JsonProperty("author")]
+ public AuthorType Author;
+
+ /*[Serializable]
public class DetailsData
{
[JsonProperty("author")]
@@ -96,35 +109,23 @@ namespace IPA.Updating.ModSaber
}
[JsonProperty("details")]
- public DetailsData Details;
+ public DetailsData Details;*/
- [Serializable]
- public class ApprovalStatus
- {
- [JsonProperty("status")]
- public bool Status;
- [JsonProperty("modified")]
- public string LastModified;
- }
+ [JsonProperty("status")]
+ public string Status;
+ public const string ApprovedStatus = "approved";
- [JsonProperty("approval")]
- public ApprovalStatus Approval;
-
- [Serializable]
- public class GameVersionType
- {
- [JsonProperty("value"),
- JsonConverter(typeof(SemverVersionConverter))]
- public Version Version;
- [JsonProperty("manifest")]
- public string Manifest;
- }
+ [JsonProperty("description")]
+ public string Description;
- [JsonProperty("gameVersion")]
- public GameVersionType GameVersion;
+ [JsonProperty("category")]
+ public string Category;
+ [JsonProperty("link")]
+ public Uri Link;
+
#pragma warning restore CS0649
- [Serializable]
+ /*[Serializable]
public class PlatformFile
{
[JsonProperty("hash"),
@@ -152,9 +153,42 @@ namespace IPA.Updating.ModSaber
}
[JsonProperty("files")]
- public FilesObject Files;
-
- public class Dependency
+ public FilesObject Files;*/
+
+ [Serializable]
+ public class DownloadsObject
+ {
+ public const string TypeUniversal = "universal";
+ public const string TypeSteam = "steam";
+ public const string TypeOculus = "oculus";
+
+ [JsonProperty("type")]
+ public string Type;
+
+ [JsonProperty("url")]
+ public string Path;
+
+ [Serializable]
+ public class HashObject
+ {
+ [JsonProperty("hash"), JsonConverter(typeof(HexArrayConverter))]
+ public byte[] Hash;
+
+ [JsonProperty("file")]
+ public string File;
+ }
+
+ ///
+ /// Hashes stored are MD5
+ ///
+ [JsonProperty("hashMd5")]
+ public HashObject[] Hashes;
+ }
+
+ [JsonProperty("downloads")]
+ public DownloadsObject[] Downloads;
+
+ /*public class Dependency
{
public string Name = null;
public Range VersionRange = null;
@@ -174,11 +208,14 @@ namespace IPA.Updating.ModSaber
public LinksType Links;
[JsonProperty("oldVersions", ItemConverterType = typeof(SemverVersionConverter))]
- public Version[] OldVersions = new Version[0];
+ public Version[] OldVersions = new Version[0];*/
+
+ [JsonProperty("dependencies")]
+ public Mod[] Dependencies;
public override string ToString()
{
- return $"{{\"{Details.Title} ({Name})\"v{Version} for {GameVersion.Version} by {Details.Author} with \"{Files.Steam}\" and \"{Files.Oculus}\"}}";
+ return $"{{\"{Name}\"v{Version} by {Author} files for {string.Join(", ", Downloads.Select(d => d.Type))}}}";
}
}
diff --git a/IPA.Loader/Updating/ModSaber/Updater.cs b/IPA.Loader/Updating/BeatMods/Updater.cs
similarity index 88%
rename from IPA.Loader/Updating/ModSaber/Updater.cs
rename to IPA.Loader/Updating/BeatMods/Updater.cs
index 64536ff4..2768da53 100644
--- a/IPA.Loader/Updating/ModSaber/Updater.cs
+++ b/IPA.Loader/Updating/BeatMods/Updater.cs
@@ -20,7 +20,7 @@ using static IPA.Loader.PluginManager;
using Logger = IPA.Logging.Logger;
using Version = SemVer.Version;
-namespace IPA.Updating.ModSaber
+namespace IPA.Updating.BeatMods
{
[SuppressMessage("ReSharper", "ClassNeverInstantiated.Global")]
internal class Updater : MonoBehaviour
@@ -72,7 +72,7 @@ namespace IPA.Updating.ModSaber
}
private readonly Dictionary requestCache = new Dictionary();
- private IEnumerator GetModsaberEndpoint(string url, Ref result)
+ private IEnumerator GetBeatModsEndpoint(string url, Ref result)
{
if (requestCache.TryGetValue(url, out string value))
{
@@ -121,11 +121,11 @@ namespace IPA.Updating.ModSaber
{
Ref reqResult = new Ref("");
- yield return GetModsaberEndpoint(uri, reqResult);
+ yield return GetBeatModsEndpoint(uri, reqResult);
try
{
- result.Value = JsonConvert.DeserializeObject(reqResult.Value);
+ result.Value = JsonConvert.DeserializeObject>(reqResult.Value).First();
modCache[uri] = result.Value;
}
@@ -137,9 +137,9 @@ namespace IPA.Updating.ModSaber
}
private readonly Dictionary> modVersionsCache = new Dictionary>();
- private IEnumerator GetModVersionsMatching(string modName, string range, Ref> result)
+ private IEnumerator GetModVersionsMatching(string modName, Range range, Ref> result)
{
- var uri = string.Format(ApiEndpoint.GetModsWithSemver, Uri.EscapeUriString(modName), Uri.EscapeUriString(range));
+ var uri = string.Format(ApiEndpoint.GetModsByName, Uri.EscapeUriString(modName));
if (modVersionsCache.TryGetValue(uri, out List value))
{
@@ -149,11 +149,12 @@ namespace IPA.Updating.ModSaber
{
Ref reqResult = new Ref("");
- yield return GetModsaberEndpoint(uri, reqResult);
+ yield return GetBeatModsEndpoint(uri, reqResult);
try
{
- result.Value = JsonConvert.DeserializeObject>(reqResult.Value);
+ result.Value = JsonConvert.DeserializeObject>(reqResult.Value)
+ .Where(m => range.IsSatisfied(m.Version)).ToList();
modVersionsCache[uri] = result.Value;
}
@@ -217,8 +218,15 @@ namespace IPA.Updating.ModSaber
continue;
}
- list.Value.AddRange(mod.Value.Links.Dependencies.Select(d => new DependencyObject { Name = d.Name, Requirement = d.VersionRange, Consumers = new HashSet { dep.Name } }));
- list.Value.AddRange(mod.Value.Links.Conflicts.Select(d => new DependencyObject { Name = d.Name, Conflicts = d.VersionRange, Consumers = new HashSet { dep.Name } }));
+ list.Value.AddRange(mod.Value.Dependencies.Select(m => new DependencyObject
+ {
+ Name = m.Name,
+ Requirement = new Range($">={m.Version}"),
+ Consumers = new HashSet { dep.Name }
+ }));
+ // currently no conflicts exist in BeatMods
+ //list.Value.AddRange(mod.Value.Links.Dependencies.Select(d => new DependencyObject { Name = d.Name, Requirement = d.VersionRange, Consumers = new HashSet { dep.Name } }));
+ //list.Value.AddRange(mod.Value.Links.Conflicts.Select(d => new DependencyObject { Name = d.Name, Conflicts = d.VersionRange, Consumers = new HashSet { dep.Name } }));
}
var depNames = new HashSet();
@@ -266,7 +274,7 @@ namespace IPA.Updating.ModSaber
}
var modsMatching = new Ref>(null);
- yield return GetModVersionsMatching(dep.Name, dep.Requirement.ToString(), modsMatching);
+ yield return GetModVersionsMatching(dep.Name, dep.Requirement, modsMatching);
try { modsMatching.Verify(); }
catch (Exception e)
{
@@ -278,8 +286,8 @@ namespace IPA.Updating.ModSaber
var ver = modsMatching.Value
.Where(nullCheck => nullCheck != null) // entry is not null
- .Where(versionCheck => versionCheck.GameVersion.Version == BeatSaber.GameVersion) // game version matches
- .Where(approvalCheck => approvalCheck.Approval.Status) // version approved
+ //.Where(versionCheck => versionCheck.GameVersion.Version == BeatSaber.GameVersion) // game version matches
+ .Where(approvalCheck => approvalCheck.Status == ApiEndpoint.Mod.ApprovedStatus) // version approved
.Where(conflictsCheck => dep.Conflicts == null || !dep.Conflicts.IsSatisfied(conflictsCheck.Version)) // not a conflicting version
.Select(mod => mod.Version).Max(); // (2.1) get the max version
// ReSharper disable once AssignmentInConditionalExpression
@@ -329,13 +337,18 @@ namespace IPA.Updating.ModSaber
yield break;
}
- ApiEndpoint.Mod.PlatformFile platformFile;
+ /*
+ ApiEndpoint.Mod.DownloadsObject platformFile;
if (BeatSaber.ReleaseType == BeatSaber.Release.Steam || mod.Value.Files.Oculus == null)
platformFile = mod.Value.Files.Steam;
else
- platformFile = mod.Value.Files.Oculus;
+ platformFile = mod.Value.Files.Oculus;*/
+
+ var releaseName = BeatSaber.ReleaseType == BeatSaber.Release.Steam
+ ? ApiEndpoint.Mod.DownloadsObject.TypeSteam : ApiEndpoint.Mod.DownloadsObject.TypeOculus;
+ var platformFile = mod.Value.Downloads.First(f => f.Type == ApiEndpoint.Mod.DownloadsObject.TypeUniversal || f.Type == releaseName);
- string url = platformFile.DownloadPath;
+ string url = ApiEndpoint.BeatModBase + platformFile.Path;
Logger.updater.Debug($"URL = {url}");
@@ -386,7 +399,7 @@ namespace IPA.Updating.ModSaber
if (downloadTask.IsFaulted)
{
- if (downloadTask.Exception != null && downloadTask.Exception.InnerExceptions.Any(e => e is ModsaberInterceptException))
+ if (downloadTask.Exception != null && downloadTask.Exception.InnerExceptions.Any(e => e is BeatmodsInterceptException))
{ // any exception is an intercept exception
Logger.updater.Error($"Modsaber did not return expected data for {item.Name}");
}
@@ -451,15 +464,15 @@ namespace IPA.Updating.ModSaber
}
}
- private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.PlatformFile fileInfo)
+ private void ExtractPluginAsync(MemoryStream stream, DependencyObject item, ApiEndpoint.Mod.DownloadsObject fileInfo)
{ // (3.3)
Logger.updater.Debug($"Extracting ZIP file for {item.Name}");
- var data = stream.GetBuffer();
+ /*var data = stream.GetBuffer();
SHA1 sha = new SHA1CryptoServiceProvider();
var hash = sha.ComputeHash(data);
if (!Utils.UnsafeCompare(hash, fileInfo.Hash))
- throw new Exception("The hash for the file doesn't match what is defined");
+ throw new Exception("The hash for the file doesn't match what is defined");*/
var targetDir = Path.Combine(BeatSaber.InstallPath, "IPA", Path.GetRandomFileName() + "_Pending");
Directory.CreateDirectory(targetDir);
@@ -489,17 +502,17 @@ namespace IPA.Updating.ModSaber
entry.Extract(ostream);
ostream.Seek(0, SeekOrigin.Begin);
- sha = new SHA1CryptoServiceProvider();
- var fileHash = sha.ComputeHash(ostream);
+ var md5 = new MD5CryptoServiceProvider();
+ var fileHash = md5.ComputeHash(ostream);
try
{
- if (!Utils.UnsafeCompare(fileHash, fileInfo.FileHashes[entry.FileName]))
+ if (!Utils.UnsafeCompare(fileHash, fileInfo.Hashes.Where(h => h.File == entry.FileName).Select(h => h.Hash).First()))
throw new Exception("The hash for the file doesn't match what is defined");
}
catch (KeyNotFoundException)
{
- throw new ModsaberInterceptException("ModSaber did not send the hashes for the zip's content!");
+ throw new BeatmodsInterceptException("BeatMods did not send the hashes for the zip's content!");
}
ostream.Seek(0, SeekOrigin.Begin);
@@ -582,21 +595,21 @@ namespace IPA.Updating.ModSaber
}
[Serializable]
- internal class ModsaberInterceptException : Exception
+ internal class BeatmodsInterceptException : Exception
{
- public ModsaberInterceptException()
+ public BeatmodsInterceptException()
{
}
- public ModsaberInterceptException(string message) : base(message)
+ public BeatmodsInterceptException(string message) : base(message)
{
}
- public ModsaberInterceptException(string message, Exception innerException) : base(message, innerException)
+ public BeatmodsInterceptException(string message, Exception innerException) : base(message, innerException)
{
}
- protected ModsaberInterceptException(SerializationInfo info, StreamingContext context) : base(info, context)
+ protected BeatmodsInterceptException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
diff --git a/IPA/Properties/AssemblyInfo.cs b/IPA/Properties/AssemblyInfo.cs
index ac459016..9769ae7e 100644
--- a/IPA/Properties/AssemblyInfo.cs
+++ b/IPA/Properties/AssemblyInfo.cs
@@ -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.12.9")]
-[assembly: AssemblyFileVersion("3.12.9")]
\ No newline at end of file
+[assembly: AssemblyVersion("3.12.10")]
+[assembly: AssemblyFileVersion("3.12.10")]
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index ca54f3e9..2f188f2d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,6 +1,6 @@
version: 'BSIPA-{branch}-{build}'
environment:
- bsipa_version: '3.12.9'
+ bsipa_version: '3.12.10'
pull_requests:
do_not_increment_build_number: true
install: