Browse Source

Fix #79 #81 using Zinga's suggestion

The config now contains a ResetGameAssembliesOnVersionChange property, which, when true, sets the GameAssemblies property to its default when a verison change is detected.
pull/86/head
Anairkoen Schno 1 year ago
parent
commit
d4adb8cdb6
No known key found for this signature in database GPG Key ID: 40F6F33603F1772D
5 changed files with 185 additions and 171 deletions
  1. +4
    -3
      IPA.Injector/GameVersionEarly.cs
  2. +4
    -2
      IPA.Injector/Injector.cs
  3. +145
    -150
      IPA.Loader/Config/Data/Value.cs
  4. +24
    -5
      IPA.Loader/Config/SelfConfig.cs
  5. +8
    -11
      IPA.Loader/Utilities/CriticalSection.cs

+ 4
- 3
IPA.Injector/GameVersionEarly.cs View File

@ -1,4 +1,5 @@
using IPA.Utilities;
#nullable enable
using IPA.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
@ -48,7 +49,7 @@ namespace IPA.Injector
}
var rewind = -sizeof(int) - sizeof(byte);
stream.Seek(rewind, SeekOrigin.Current); // rewind to the string length
_ = stream.Seek(rewind, SeekOrigin.Current); // rewind to the string length
var strlen = reader.ReadInt32();
var strbytes = reader.ReadBytes(strlen);
@ -57,7 +58,7 @@ namespace IPA.Injector
}
}
internal static AlmostVersion SafeParseVersion() => new AlmostVersion(GetGameVersion());
internal static AlmostVersion SafeParseVersion() => new(GetGameVersion());
private static void _Load()
{


+ 4
- 2
IPA.Injector/Injector.cs View File

@ -80,11 +80,13 @@ namespace IPA.Injector
Logging.Logger.Injector.Debug("Prepping bootstrapper");
// make sure to load the game version and check boundaries before installing the bootstrap, because that uses the game assemblies property
GameVersionEarly.Load();
SelfConfig.Instance.CheckVersionBoundary();
// updates backup
InstallBootstrapPatch();
GameVersionEarly.Load();
AntiMalwareEngine.Initialize();
Updates.InstallPendingUpdates();


+ 145
- 150
IPA.Loader/Config/Data/Value.cs View File

@ -1,151 +1,146 @@
#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
#nullable enable
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IPA.Config.Data
{
/// <summary>
/// A base value type for config data abstract representations, to be serialized with an
/// <see cref="IConfigProvider"/>. If a <see cref="Value"/> is <see langword="null"/>, then
/// that represents just that: a <c>null</c> in whatever serialization is being used.
/// Also contains factory functions for all derived types.
/// </summary>
public abstract class Value
{
/// <summary>
/// Converts this <see cref="Value"/> into a human-readable format.
/// </summary>
/// <returns>a human-readable string containing the value provided</returns>
public abstract override string ToString();
/// <summary>
/// Creates a Null <see cref="Value"/>.
/// </summary>
/// <returns><see langword="null"/></returns>
public static Value? Null() => null;
/// <summary>
/// Creates an empty <see cref="List"/>.
/// </summary>
/// <returns>an empty <see cref="List"/></returns>
/// <seealso cref="From(IEnumerable{Value})"/>
public static List List() => new();
/// <summary>
/// Creates an empty <see cref="Map"/>.
/// </summary>
/// <returns>an empty <see cref="Map"/></returns>
/// <seealso cref="From(IDictionary{string, Value})"/>
/// <seealso cref="From(IEnumerable{KeyValuePair{string, Value}})"/>
public static Map Map() => new();
/// <summary>
/// Creates a new <see cref="Value"/> representing a <see cref="string"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Text"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Text(string)"/>
[return: NotNullIfNotNull("val")]
public static Text? From(string? val) => Text(val);
/// <summary>
/// Creates a new <see cref="Data.Text"/> object wrapping a <see cref="string"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Text"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(string)"/>
[return: NotNullIfNotNull("val")]
public static Text? Text(string? val) => val == null ? null : new(val);
/// <summary>
/// Creates a new <see cref="Value"/> wrapping a <see cref="long"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Integer"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Integer(long)"/>
public static Integer From(long val) => Integer(val);
/// <summary>
/// Creates a new <see cref="Data.Integer"/> wrapping a <see cref="long"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Integer"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(long)"/>
public static Integer Integer(long val) => new(val);
/// <summary>
/// Creates a new <see cref="Value"/> wrapping a <see cref="double"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="FloatingPoint"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Float(decimal)"/>
public static FloatingPoint From(decimal val) => Float(val);
/// <summary>
/// Creates a new <see cref="FloatingPoint"/> wrapping a <see cref="decimal"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="FloatingPoint"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(decimal)"/>
public static FloatingPoint Float(decimal val) => new(val);
/// <summary>
/// Creates a new <see cref="Value"/> wrapping a <see cref="bool"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Boolean"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Bool(bool)"/>
public static Boolean From(bool val) => Bool(val);
/// <summary>
/// Creates a new <see cref="Boolean"/> wrapping a <see cref="bool"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Boolean"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(bool)"/>
public static Boolean Bool(bool val) => new(val);
/// <summary>
/// Creates a new <see cref="Data.List"/> holding the content of an <see cref="IEnumerable{T}"/>
/// of <see cref="Value"/>.
/// </summary>
/// <param name="vals">the <see cref="Value"/>s to initialize the <see cref="Data.List"/> with</param>
/// <returns>a <see cref="Data.List"/> containing the content of <paramref name="vals"/></returns>
/// <seealso cref="List"/>
[return: NotNullIfNotNull("vals")]
public static List? From(IEnumerable<Value?>? vals)
{
if (vals is null) return null;
var l = List();
l.AddRange(vals);
return l;
}
/// <summary>
/// Creates a new <see cref="Data.Map"/> holding the content of an <see cref="IDictionary{TKey, TValue}"/>
/// of <see cref="string"/> to <see cref="Value"/>.
/// </summary>
/// <param name="vals">the dictionary of <see cref="Value"/>s to initialize the <see cref="Data.Map"/> wtih</param>
/// <returns>a <see cref="Data.Map"/> containing the content of <paramref name="vals"/></returns>
/// <seealso cref="Map"/>
/// <seealso cref="From(IEnumerable{KeyValuePair{string, Value}})"/>
public static Map From(IDictionary<string, Value?> vals) => From(vals as IEnumerable<KeyValuePair<string, Value?>>);
/// <summary>
/// Creates a new <see cref="Data.Map"/> holding the content of an <see cref="IEnumerable{T}"/>
/// of <see cref="KeyValuePair{TKey, TValue}"/> of <see cref="string"/> to <see cref="Value"/>.
/// </summary>
/// <param name="vals">the enumerable of <see cref="KeyValuePair{TKey, TValue}"/> of name to <see cref="Value"/></param>
/// <returns>a <see cref="Data.Map"/> containing the content of <paramref name="vals"/></returns>
/// <seealso cref="Map"/>
/// <seealso cref="From(IDictionary{string, Value})"/>
[return: NotNullIfNotNull("vals")]
public static Map? From(IEnumerable<KeyValuePair<string, Value?>>? vals)
{
if (vals is null) return null;
var m = Map();
foreach (var v in vals) m.Add(v.Key, v.Value);
return m;
}
}
}
namespace IPA.Config.Data
{
/// <summary>
/// A base value type for config data abstract representations, to be serialized with an
/// <see cref="IConfigProvider"/>. If a <see cref="Value"/> is <see langword="null"/>, then
/// that represents just that: a <c>null</c> in whatever serialization is being used.
/// Also contains factory functions for all derived types.
/// </summary>
public abstract class Value
{
/// <summary>
/// Converts this <see cref="Value"/> into a human-readable format.
/// </summary>
/// <returns>a human-readable string containing the value provided</returns>
public abstract override string ToString();
/// <summary>
/// Creates a Null <see cref="Value"/>.
/// </summary>
/// <returns><see langword="null"/></returns>
public static Value? Null() => null;
/// <summary>
/// Creates an empty <see cref="List"/>.
/// </summary>
/// <returns>an empty <see cref="List"/></returns>
/// <seealso cref="From(IEnumerable{Value})"/>
public static List List() => new();
/// <summary>
/// Creates an empty <see cref="Map"/>.
/// </summary>
/// <returns>an empty <see cref="Map"/></returns>
/// <seealso cref="From(IDictionary{string, Value})"/>
/// <seealso cref="From(IEnumerable{KeyValuePair{string, Value}})"/>
public static Map Map() => new();
/// <summary>
/// Creates a new <see cref="Value"/> representing a <see cref="string"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Text"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Text(string)"/>
[return: NotNullIfNotNull("val")]
public static Text? From(string? val) => Text(val);
/// <summary>
/// Creates a new <see cref="Data.Text"/> object wrapping a <see cref="string"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Text"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(string)"/>
[return: NotNullIfNotNull("val")]
public static Text? Text(string? val) => val == null ? null : new(val);
/// <summary>
/// Creates a new <see cref="Value"/> wrapping a <see cref="long"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Integer"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Integer(long)"/>
public static Integer From(long val) => Integer(val);
/// <summary>
/// Creates a new <see cref="Data.Integer"/> wrapping a <see cref="long"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Data.Integer"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(long)"/>
public static Integer Integer(long val) => new(val);
/// <summary>
/// Creates a new <see cref="Value"/> wrapping a <see cref="double"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="FloatingPoint"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Float(decimal)"/>
public static FloatingPoint From(decimal val) => Float(val);
/// <summary>
/// Creates a new <see cref="FloatingPoint"/> wrapping a <see cref="decimal"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="FloatingPoint"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(decimal)"/>
public static FloatingPoint Float(decimal val) => new(val);
/// <summary>
/// Creates a new <see cref="Value"/> wrapping a <see cref="bool"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Boolean"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="Bool(bool)"/>
public static Boolean From(bool val) => Bool(val);
/// <summary>
/// Creates a new <see cref="Boolean"/> wrapping a <see cref="bool"/>.
/// </summary>
/// <param name="val">the value to wrap</param>
/// <returns>a <see cref="Boolean"/> wrapping <paramref name="val"/></returns>
/// <seealso cref="From(bool)"/>
public static Boolean Bool(bool val) => new(val);
/// <summary>
/// Creates a new <see cref="Data.List"/> holding the content of an <see cref="IEnumerable{T}"/>
/// of <see cref="Value"/>.
/// </summary>
/// <param name="vals">the <see cref="Value"/>s to initialize the <see cref="Data.List"/> with</param>
/// <returns>a <see cref="Data.List"/> containing the content of <paramref name="vals"/></returns>
/// <seealso cref="List"/>
[return: NotNullIfNotNull("vals")]
public static List? From(IEnumerable<Value?>? vals)
{
if (vals is null) return null;
var l = List();
l.AddRange(vals);
return l;
}
/// <summary>
/// Creates a new <see cref="Data.Map"/> holding the content of an <see cref="IDictionary{TKey, TValue}"/>
/// of <see cref="string"/> to <see cref="Value"/>.
/// </summary>
/// <param name="vals">the dictionary of <see cref="Value"/>s to initialize the <see cref="Data.Map"/> wtih</param>
/// <returns>a <see cref="Data.Map"/> containing the content of <paramref name="vals"/></returns>
/// <seealso cref="Map"/>
/// <seealso cref="From(IEnumerable{KeyValuePair{string, Value}})"/>
public static Map From(IDictionary<string, Value?> vals) => From(vals as IEnumerable<KeyValuePair<string, Value?>>);
/// <summary>
/// Creates a new <see cref="Data.Map"/> holding the content of an <see cref="IEnumerable{T}"/>
/// of <see cref="KeyValuePair{TKey, TValue}"/> of <see cref="string"/> to <see cref="Value"/>.
/// </summary>
/// <param name="vals">the enumerable of <see cref="KeyValuePair{TKey, TValue}"/> of name to <see cref="Value"/></param>
/// <returns>a <see cref="Data.Map"/> containing the content of <paramref name="vals"/></returns>
/// <seealso cref="Map"/>
/// <seealso cref="From(IDictionary{string, Value})"/>
[return: NotNullIfNotNull("vals")]
public static Map? From(IEnumerable<KeyValuePair<string, Value?>>? vals)
{
if (vals is null) return null;
var m = Map();
foreach (var v in vals) m.Add(v.Key, v.Value);
return m;
}
}
}

+ 24
- 5
IPA.Loader/Config/SelfConfig.cs View File

@ -54,7 +54,7 @@ namespace IPA.Config
CommandLineValues.YeetMods = false;
break;
case "--no-logs":
CommandLineValues.WriteLogs = true;
CommandLineValues.WriteLogs = false;
break;
case "--condense-logs":
CommandLineValues.Debug.CondenseModLogs = true;
@ -75,6 +75,14 @@ namespace IPA.Config
}
}
public void CheckVersionBoundary()
{
if (ResetGameAssebliesOnVersionChange && Utilities.UnityGame.IsGameVersionBoundary)
{
GameAssemblies = GetDefaultGameAssemblies();
}
}
internal const string IPAName = "Beat Saber IPA";
internal const string IPAVersion = "4.2.2.0";
@ -180,19 +188,30 @@ namespace IPA.Config
[JsonIgnore]
public bool WriteLogs { get; set; } = true;
public virtual bool ResetGameAssebliesOnVersionChange { get; set; } = true;
// LINE: ignore
[NonNullable, UseConverter(typeof(CollectionConverter<string, HashSet<string?>>))]
public virtual HashSet<string> GameAssemblies { get; set; } = new HashSet<string>
public virtual HashSet<string> GameAssemblies { get; set; } = GetDefaultGameAssemblies();
// BEGIN: section ignore
public static HashSet<string> GetDefaultGameAssemblies()
=> new()
{
// LINE: ignore 5
#if BeatSaber // provide these defaults only for Beat Saber builds
"Main.dll", "Core.dll", "HMLib.dll", "HMUI.dll", "HMRendering.dll", "VRUI.dll",
"Main.dll", "Core.dll", "HMLib.dll", "HMUI.dll", "HMRendering.dll", "VRUI.dll",
"BeatmapCore.dll", "GameplayCore.dll","HMLibAttributes.dll",
#else // otherwise specify Assembly-CSharp.dll
"Assembly-CSharp.dll"
// LINE: ignore
#endif
};
// END: section ignore
// LINE: ignore
#if false // used to make schema gen happy
private static HashSet<string> GetDefaultGameAssemblies() => null;
// LINE: ignore
#endif
// LINE: ignore
public static HashSet<string> GameAssemblies_ => Instance?.GameAssemblies ?? new HashSet<string> { "Assembly-CSharp.dll" };


+ 8
- 11
IPA.Loader/Utilities/CriticalSection.cs View File

@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
#nullable enable
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using IPA.Logging;
namespace IPA.Utilities
@ -21,9 +18,9 @@ namespace IPA.Utilities
ResetExitHandlers();
}
private static void Reset(object sender, EventArgs e)
private static void Reset(object? sender, EventArgs? e)
{
Win32.SetConsoleCtrlHandler(registeredHandler, false);
_ = Win32.SetConsoleCtrlHandler(registeredHandler, false);
WinHttp.SetPeekMessageHook(null);
}
@ -32,8 +29,8 @@ namespace IPA.Utilities
private static readonly Win32.ConsoleCtrlDelegate registeredHandler = HandleExit;
internal static void ResetExitHandlers()
{
Win32.SetConsoleCtrlHandler(registeredHandler, false);
Win32.SetConsoleCtrlHandler(registeredHandler, true);
_ = Win32.SetConsoleCtrlHandler(registeredHandler, false);
_ = Win32.SetConsoleCtrlHandler(registeredHandler, true);
WinHttp.SetPeekMessageHook(PeekMessageHook);
AppDomain.CurrentDomain.ProcessExit -= OnProcessExit;
@ -60,14 +57,14 @@ namespace IPA.Utilities
[DllImport("bsipa-doorstop")]
public static extern void SetPeekMessageHook(
[MarshalAs(UnmanagedType.FunctionPtr)]
PeekMessageHook hook);
PeekMessageHook? hook);
[DllImport("bsipa-doorstop")]
public static extern void SetIgnoreUnhandledExceptions(
[MarshalAs(UnmanagedType.Bool)] bool ignore);
}
private static Win32.ConsoleCtrlDelegate _handler = null;
private static Win32.ConsoleCtrlDelegate? _handler = null;
private static volatile bool isInExecuteSection = false;
// returns true to continue looping and calling PeekMessage


Loading…
Cancel
Save