diff --git a/IPA.Loader/Config/SelfConfig.cs b/IPA.Loader/Config/SelfConfig.cs
index 57856357..83f1e8d3 100644
--- a/IPA.Loader/Config/SelfConfig.cs
+++ b/IPA.Loader/Config/SelfConfig.cs
@@ -68,7 +68,7 @@ namespace IPA.Config
}
internal const string IPAName = "Beat Saber IPA";
- internal const string IPAVersion = "3.99.99.10";
+ internal const string IPAVersion = "3.99.99.11";
// uses Updates.AutoUpdate, Updates.AutoCheckUpdates, YeetMods, Debug.ShowCallSource, Debug.ShowDebug,
// Debug.CondenseModLogs
diff --git a/IPA.Loader/Loader/manifest.json b/IPA.Loader/Loader/manifest.json
index c5487c0d..5357df61 100644
--- a/IPA.Loader/Loader/manifest.json
+++ b/IPA.Loader/Loader/manifest.json
@@ -5,10 +5,10 @@
"#![IPA.Loader.description.md]",
"A mod loader specifically for Beat Saber."
],
- "gameVersion": "1.8.0b1",
+ "gameVersion": "1.8.0b2",
"id": "BSIPA",
"name": "Beat Saber IPA",
- "version": "4.0.0-beta.10",
+ "version": "4.0.0-beta.11",
"icon": "IPA.icon_white.png",
"features": [
"define-feature(print, IPA.Loader.Features.PrintFeature)",
diff --git a/IPA.Loader/Utilities/Utils.cs b/IPA.Loader/Utilities/Utils.cs
index e3931e28..028848b8 100644
--- a/IPA.Loader/Utilities/Utils.cs
+++ b/IPA.Loader/Utilities/Utils.cs
@@ -1,246 +1,246 @@
-using System;
-using System.IO;
-using System.Text;
-using System.Linq;
-using System.Collections.Generic;
-using Mono.Cecil;
-using System.Runtime.CompilerServices;
+using System;
+using System.IO;
+using System.Text;
+using System.Linq;
+using System.Collections.Generic;
+using Mono.Cecil;
+using System.Runtime.CompilerServices;
using System.Threading;
-#if NET3
-using File = Net3_Proxy.File;
-#endif
+#if NET3
+using File = Net3_Proxy.File;
+#endif
-namespace IPA.Utilities
-{
- ///
- /// A class providing static utility functions that in any other language would just *exist*.
- ///
- public static class Utils
- {
- ///
- /// Converts a hex string to a byte array.
- ///
- /// the hex stream
- /// the corresponding byte array
- public static byte[] StringToByteArray(string hex)
- {
- int numberChars = hex.Length;
- byte[] bytes = new byte[numberChars / 2];
- for (int i = 0; i < numberChars; i += 2)
- bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
- return bytes;
- }
-
- ///
- /// Converts a byte array to a hex string.
- ///
- /// the byte array
- /// the hex form of the array
- public static string ByteArrayToString(byte[] ba)
- {
- StringBuilder hex = new StringBuilder(ba.Length * 2);
- foreach (byte b in ba)
- hex.AppendFormat("{0:x2}", b);
- return hex.ToString();
- }
-
- // Copyright (c) 2008-2013 Hafthor Stefansson
- // Distributed under the MIT/X11 software license
- // Ref: http://www.opensource.org/licenses/mit-license.php.
- // From: https://stackoverflow.com/a/8808245/3117125
- ///
- /// Uses unsafe code to compare 2 byte arrays quickly.
- ///
- /// array 1
- /// array 2
- /// whether or not they are byte-for-byte equal
- public static unsafe bool UnsafeCompare(byte[] a1, byte[] a2)
- {
- if (a1 == a2) return true;
- if (a1 == null || a2 == null || a1.Length != a2.Length)
- return false;
- fixed (byte* p1 = a1, p2 = a2)
- {
- byte* x1 = p1, x2 = p2;
- int l = a1.Length;
- for (int i = 0; i < l / 8; i++, x1 += 8, x2 += 8)
- if (*((long*)x1) != *((long*)x2)) return false;
- if ((l & 4) != 0) { if (*((int*)x1) != *((int*)x2)) return false; x1 += 4; x2 += 4; }
- if ((l & 2) != 0) { if (*((short*)x1) != *((short*)x2)) return false; x1 += 2; x2 += 2; }
- if ((l & 1) != 0) if (*x1 != *x2) return false;
- return true;
- }
- }
-
- ///
- /// Gets a path relative to the provided folder.
- ///
- /// the file to relativize
- /// the source folder
- /// a path to get from to
- public static string GetRelativePath(string file, string folder)
- {
- Uri pathUri = new Uri(file);
- // Folders must end in a slash
- if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
- {
- folder += Path.DirectorySeparatorChar;
- }
- Uri folderUri = new Uri(folder);
- return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
- }
-
- ///
- /// Copies all files from to .
- ///
- /// the source directory
- /// the destination directory
- /// the filename of the file to append together
- /// a delegate called when there is an error copying. Return true to keep going.
- public static void CopyAll(DirectoryInfo source, DirectoryInfo target, string appendFileName = "",
- Func onCopyException = null)
- {
- if (source.FullName.ToLower() == target.FullName.ToLower())
- {
- return;
- }
-
- // Check if the target directory exists, if not, create it.
- if (Directory.Exists(target.FullName) == false)
- {
- Directory.CreateDirectory(target.FullName);
- }
-
- // Copy each file into it's new directory.
- foreach (FileInfo fi in source.GetFiles())
- {
- try
- {
- if (fi.Name == appendFileName)
- File.AppendAllLines(Path.Combine(target.ToString(), fi.Name), File.ReadAllLines(fi.FullName));
- else
- fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
- }
- catch (Exception e)
- {
- var keepOn = onCopyException?.Invoke(e, fi);
- if (!keepOn.Unwrap())
- throw;
- }
- }
-
- // Copy each subdirectory using recursion.
- foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
- {
- DirectoryInfo nextTargetSubDir =
- target.CreateSubdirectory(diSourceSubDir.Name);
- CopyAll(diSourceSubDir, nextTargetSubDir, appendFileName, onCopyException);
- }
- }
-
- ///
- /// Whether you can safely use without Mono throwing a fit.
- ///
- /// if you can use safely, otherwise
- public static bool CanUseDateTimeNowSafely { get; private set; } = true;
- private static bool DateTimeSafetyUnknown = true;
- private static long UnsafeAdvanceTicks = 1;
-
- ///
- /// Gets the current if supported, otherwise, if Mono would throw a fit,
- /// returns plus some value, such that each time it is called
- /// the value will be greater than the previous result. Not suitable for timing.
- ///
- /// the current if supported, otherwise some indeterminant increasing value.
- public static DateTime CurrentTime()
- {
- if (DateTimeSafetyUnknown)
- {
- DateTime time = DateTime.MinValue;
- try
- {
- time = DateTime.Now;
- }
- catch (TimeZoneNotFoundException)
- { // Mono did a fucky wucky and we need to avoid this call
- CanUseDateTimeNowSafely = false;
- }
- DateTimeSafetyUnknown = false;
- return time;
- }
- else
- {
- if (CanUseDateTimeNowSafely) return DateTime.Now;
- else return DateTime.MinValue.AddTicks(Interlocked.Increment(ref UnsafeAdvanceTicks)); // return MinValue as a fallback
- }
- }
-
- ///
- /// Compares a pair of s ignoring both the prerelease and build fields.
- ///
- /// the left value
- /// the right value
- /// < 0 if l is less than r, 0 if they are equal in the numeric portion, or > 0 if l is greater than r
- public static int VersionCompareNoPrerelease(SemVer.Version l, SemVer.Version r)
- {
- var cmpVal = l.Major - r.Major;
- if (cmpVal != 0) return cmpVal;
- cmpVal = l.Minor - r.Minor;
- if (cmpVal != 0) return cmpVal;
- cmpVal = l.Patch - r.Patch;
- return cmpVal;
- }
-
- ///
- /// An object used to manage scope guards.
- ///
- ///
- ///
- /// using var _ = new Utils.ScopeGuardObject(() => RunOnScopeExit(value));
- ///
- ///
- ///
- public struct ScopeGuardObject : IDisposable
- {
- private readonly Action action;
- ///
- /// Creates a new scope guard that will invoke when disposed.
- ///
- /// the action to run on dispose
- public ScopeGuardObject(Action action)
- => this.action = action;
- void IDisposable.Dispose()
- => action?.Invoke();
- }
-
- ///
- /// Creates a scope guard for a given .
- ///
- /// the to run on dispose
- /// a that will run on disposal
- ///
- ///
- /// using var _ = Utils.ScopeGuard(() => RunOnScopeExit(value));
- ///
- ///
- public static ScopeGuardObject ScopeGuard(Action action)
- => new ScopeGuardObject(action);
-
- internal static bool HasInterface(this TypeDefinition type, string interfaceFullName)
- {
- return (type?.Interfaces?.Any(i => i.InterfaceType.FullName == interfaceFullName) ?? false)
- || (type?.Interfaces?.Any(t => HasInterface(t?.InterfaceType?.Resolve(), interfaceFullName)) ?? false);
- }
-
-#if NET4
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static IEnumerable StrJP(this IEnumerable a) => a;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static IEnumerable StrJP(this IEnumerable a) => a.Select(o => $"{o}" /* safer than .ToString() */);
-#endif
-#if NET3
- internal static string[] StrJP(this IEnumerable a) => a.ToArray();
- internal static string[] StrJP(this IEnumerable a) => a.Select(o => $"{o}" /* safer than .ToString() */).ToArray();
-#endif
- }
-}
+namespace IPA.Utilities
+{
+ ///
+ /// A class providing static utility functions that in any other language would just *exist*.
+ ///
+ public static class Utils
+ {
+ ///
+ /// Converts a hex string to a byte array.
+ ///
+ /// the hex stream
+ /// the corresponding byte array
+ public static byte[] StringToByteArray(string hex)
+ {
+ int numberChars = hex.Length;
+ byte[] bytes = new byte[numberChars / 2];
+ for (int i = 0; i < numberChars; i += 2)
+ bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
+ return bytes;
+ }
+
+ ///
+ /// Converts a byte array to a hex string.
+ ///
+ /// the byte array
+ /// the hex form of the array
+ public static string ByteArrayToString(byte[] ba)
+ {
+ StringBuilder hex = new StringBuilder(ba.Length * 2);
+ foreach (byte b in ba)
+ hex.AppendFormat("{0:x2}", b);
+ return hex.ToString();
+ }
+
+ // Copyright (c) 2008-2013 Hafthor Stefansson
+ // Distributed under the MIT/X11 software license
+ // Ref: http://www.opensource.org/licenses/mit-license.php.
+ // From: https://stackoverflow.com/a/8808245/3117125
+ ///
+ /// Uses unsafe code to compare 2 byte arrays quickly.
+ ///
+ /// array 1
+ /// array 2
+ /// whether or not they are byte-for-byte equal
+ public static unsafe bool UnsafeCompare(byte[] a1, byte[] a2)
+ {
+ if (a1 == a2) return true;
+ if (a1 == null || a2 == null || a1.Length != a2.Length)
+ return false;
+ fixed (byte* p1 = a1, p2 = a2)
+ {
+ byte* x1 = p1, x2 = p2;
+ int l = a1.Length;
+ for (int i = 0; i < l / 8; i++, x1 += 8, x2 += 8)
+ if (*((long*)x1) != *((long*)x2)) return false;
+ if ((l & 4) != 0) { if (*((int*)x1) != *((int*)x2)) return false; x1 += 4; x2 += 4; }
+ if ((l & 2) != 0) { if (*((short*)x1) != *((short*)x2)) return false; x1 += 2; x2 += 2; }
+ if ((l & 1) != 0) if (*x1 != *x2) return false;
+ return true;
+ }
+ }
+
+ ///
+ /// Gets a path relative to the provided folder.
+ ///
+ /// the file to relativize
+ /// the source folder
+ /// a path to get from to
+ public static string GetRelativePath(string file, string folder)
+ {
+ Uri pathUri = new Uri(file);
+ // Folders must end in a slash
+ if (!folder.EndsWith(Path.DirectorySeparatorChar.ToString()))
+ {
+ folder += Path.DirectorySeparatorChar;
+ }
+ Uri folderUri = new Uri(folder);
+ return Uri.UnescapeDataString(folderUri.MakeRelativeUri(pathUri).ToString().Replace('/', Path.DirectorySeparatorChar));
+ }
+
+ ///
+ /// Copies all files from to .
+ ///
+ /// the source directory
+ /// the destination directory
+ /// the filename of the file to append together
+ /// a delegate called when there is an error copying. Return true to keep going.
+ public static void CopyAll(DirectoryInfo source, DirectoryInfo target, string appendFileName = "",
+ Func onCopyException = null)
+ {
+ if (source.FullName.ToLower() == target.FullName.ToLower())
+ {
+ return;
+ }
+
+ // Check if the target directory exists, if not, create it.
+ if (Directory.Exists(target.FullName) == false)
+ {
+ Directory.CreateDirectory(target.FullName);
+ }
+
+ // Copy each file into it's new directory.
+ foreach (FileInfo fi in source.GetFiles())
+ {
+ try
+ {
+ if (fi.Name == appendFileName)
+ File.AppendAllLines(Path.Combine(target.ToString(), fi.Name), File.ReadAllLines(fi.FullName));
+ else
+ fi.CopyTo(Path.Combine(target.ToString(), fi.Name), true);
+ }
+ catch (Exception e)
+ {
+ var keepOn = onCopyException?.Invoke(e, fi);
+ if (!keepOn.Unwrap())
+ throw;
+ }
+ }
+
+ // Copy each subdirectory using recursion.
+ foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
+ {
+ DirectoryInfo nextTargetSubDir =
+ target.CreateSubdirectory(diSourceSubDir.Name);
+ CopyAll(diSourceSubDir, nextTargetSubDir, appendFileName, onCopyException);
+ }
+ }
+
+ ///
+ /// Whether you can safely use without Mono throwing a fit.
+ ///
+ /// if you can use safely, otherwise
+ public static bool CanUseDateTimeNowSafely { get; private set; } = true;
+ private static bool DateTimeSafetyUnknown = true;
+ private static long UnsafeAdvanceTicks = 1;
+
+ ///
+ /// Gets the current if supported, otherwise, if Mono would throw a fit,
+ /// returns plus some value, such that each time it is called
+ /// the value will be greater than the previous result. Not suitable for timing.
+ ///
+ /// the current if supported, otherwise some indeterminant increasing value.
+ public static DateTime CurrentTime()
+ {
+ if (DateTimeSafetyUnknown)
+ {
+ DateTime time = DateTime.MinValue;
+ try
+ {
+ time = DateTime.Now;
+ }
+ catch (TimeZoneNotFoundException)
+ { // Mono did a fucky wucky and we need to avoid this call
+ CanUseDateTimeNowSafely = false;
+ }
+ DateTimeSafetyUnknown = false;
+ return time;
+ }
+ else
+ {
+ if (CanUseDateTimeNowSafely) return DateTime.Now;
+ else return DateTime.MinValue.AddTicks(Interlocked.Increment(ref UnsafeAdvanceTicks)); // return MinValue as a fallback
+ }
+ }
+
+ ///
+ /// Compares a pair of s ignoring both the prerelease and build fields.
+ ///
+ /// the left value
+ /// the right value
+ /// < 0 if l is less than r, 0 if they are equal in the numeric portion, or > 0 if l is greater than r
+ public static int VersionCompareNoPrerelease(SemVer.Version l, SemVer.Version r)
+ {
+ var cmpVal = l.Major - r.Major;
+ if (cmpVal != 0) return cmpVal;
+ cmpVal = l.Minor - r.Minor;
+ if (cmpVal != 0) return cmpVal;
+ cmpVal = l.Patch - r.Patch;
+ return cmpVal;
+ }
+
+ ///
+ /// An object used to manage scope guards.
+ ///
+ ///
+ ///
+ /// using var _ = new Utils.ScopeGuardObject(() => RunOnScopeExit(value));
+ ///
+ ///
+ ///
+ public struct ScopeGuardObject : IDisposable
+ {
+ private readonly Action action;
+ ///
+ /// Creates a new scope guard that will invoke when disposed.
+ ///
+ /// the action to run on dispose
+ public ScopeGuardObject(Action action)
+ => this.action = action;
+ void IDisposable.Dispose()
+ => action?.Invoke();
+ }
+
+ ///
+ /// Creates a scope guard for a given .
+ ///
+ /// the to run on dispose
+ /// a that will run on disposal
+ ///
+ ///
+ /// using var _ = Utils.ScopeGuard(() => RunOnScopeExit(value));
+ ///
+ ///
+ public static ScopeGuardObject ScopeGuard(Action action)
+ => new ScopeGuardObject(action);
+
+ internal static bool HasInterface(this TypeDefinition type, string interfaceFullName)
+ {
+ return (type?.Interfaces?.Any(i => i.InterfaceType.FullName == interfaceFullName) ?? false)
+ || (type?.Interfaces?.Any(t => HasInterface(t?.InterfaceType?.Resolve(), interfaceFullName)) ?? false);
+ }
+
+#if NET4
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static IEnumerable StrJP(this IEnumerable a) => a;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static IEnumerable StrJP(this IEnumerable a) => a.Select(o => $"{o}" /* safer than .ToString() */);
+#endif
+#if NET3
+ internal static string[] StrJP(this IEnumerable a) => a.ToArray();
+ internal static string[] StrJP(this IEnumerable a) => a.Select(o => $"{o}" /* safer than .ToString() */).ToArray();
+#endif
+ }
+}
diff --git a/IPA/Program.cs b/IPA/Program.cs
index 1bc0231f..0243b9f1 100644
--- a/IPA/Program.cs
+++ b/IPA/Program.cs
@@ -23,7 +23,7 @@ namespace IPA
Unknown
}
- public const string FileVersion = "3.99.99.10";
+ public const string FileVersion = "3.99.99.11";
public static Version Version => Assembly.GetEntryAssembly().GetName().Version;
diff --git a/Refs/Main.dll b/Refs/Main.dll
new file mode 100644
index 00000000..509f50f8
Binary files /dev/null and b/Refs/Main.dll differ
diff --git a/Refs/Unity.TextMeshPro.dll b/Refs/Unity.TextMeshPro.dll
index 957aba6e..397fc3af 100644
Binary files a/Refs/Unity.TextMeshPro.dll and b/Refs/Unity.TextMeshPro.dll differ
diff --git a/Refs/UnityEngine.CoreModule.Net4.dll b/Refs/UnityEngine.CoreModule.Net4.dll
index 872881e5..45c11737 100644
Binary files a/Refs/UnityEngine.CoreModule.Net4.dll and b/Refs/UnityEngine.CoreModule.Net4.dll differ
diff --git a/Refs/UnityEngine.UI.dll b/Refs/UnityEngine.UI.dll
index 57ac8e0b..bb1d0707 100644
Binary files a/Refs/UnityEngine.UI.dll and b/Refs/UnityEngine.UI.dll differ
diff --git a/appveyor.yml b/appveyor.yml
index a053ce08..7da3e5d7 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,7 +1,7 @@
version: 'BSIPA-{branch}-{build}'
environment:
- bsipa_version: '4.0.0-beta.10'
+ bsipa_version: '4.0.0-beta.11'
gh_token:
secure: E42gl/yepETuoLSwbJZ1GmEIPK6cCJu6zkd59NA21XiICtEV6COOLW7aehi1tcVU