|
|
@ -1,6 +1,9 @@ |
|
|
|
using IPA.Config; |
|
|
|
#nullable enable |
|
|
|
using IPA.Config; |
|
|
|
using IPA.Utilities.Async; |
|
|
|
using System; |
|
|
|
using System.Diagnostics; |
|
|
|
using System.Diagnostics.CodeAnalysis; |
|
|
|
using System.IO; |
|
|
|
using System.Reflection; |
|
|
|
using System.Runtime.CompilerServices; |
|
|
@ -17,12 +20,12 @@ namespace IPA.Utilities |
|
|
|
/// </summary>
|
|
|
|
public static class UnityGame |
|
|
|
{ |
|
|
|
private static AlmostVersion _gameVersion; |
|
|
|
private static AlmostVersion? _gameVersion; |
|
|
|
/// <summary>
|
|
|
|
/// Provides the current game version.
|
|
|
|
/// </summary>
|
|
|
|
/// <value>the SemVer version of the game</value>
|
|
|
|
public static AlmostVersion GameVersion => _gameVersion ?? (_gameVersion = new AlmostVersion(ApplicationVersionProxy)); |
|
|
|
public static AlmostVersion GameVersion => _gameVersion ??= new AlmostVersion(ApplicationVersionProxy); |
|
|
|
|
|
|
|
internal static void SetEarlyGameVersion(AlmostVersion ver) |
|
|
|
{ |
|
|
@ -76,24 +79,30 @@ namespace IPA.Utilities |
|
|
|
} |
|
|
|
|
|
|
|
internal static bool IsGameVersionBoundary { get; private set; } |
|
|
|
internal static AlmostVersion OldVersion { get; private set; } |
|
|
|
internal static AlmostVersion? OldVersion { get; private set; } |
|
|
|
internal static void CheckGameVersionBoundary() |
|
|
|
{ |
|
|
|
var gameVer = GameVersion; |
|
|
|
var lastVerS = SelfConfig.LastGameVersion_; |
|
|
|
OldVersion = lastVerS != null ? new AlmostVersion(lastVerS, gameVer) : null; |
|
|
|
|
|
|
|
IsGameVersionBoundary = OldVersion != null && gameVer != OldVersion; |
|
|
|
IsGameVersionBoundary = OldVersion is not null && gameVer != OldVersion; |
|
|
|
|
|
|
|
SelfConfig.Instance.LastGameVersion = gameVer.ToString(); |
|
|
|
} |
|
|
|
|
|
|
|
private static Thread mainThread; |
|
|
|
private static Thread? mainThread; |
|
|
|
/// <summary>
|
|
|
|
/// Checks if the currently running code is running on the Unity main thread.
|
|
|
|
/// </summary>
|
|
|
|
/// <value><see langword="true"/> if the curent thread is the Unity main thread, <see langword="false"/> otherwise</value>
|
|
|
|
public static bool OnMainThread => Thread.CurrentThread.ManagedThreadId == mainThread?.ManagedThreadId; |
|
|
|
public static bool OnMainThread => Environment.CurrentManagedThreadId == mainThread?.ManagedThreadId; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Asynchronously switches the current execution context to the Unity main thread.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>An awaitable which causes any following code to execute on the main thread.</returns>
|
|
|
|
public static SwitchToUnityMainThreadAwaitable SwitchToMainThreadAsync() => default; |
|
|
|
|
|
|
|
internal static void SetMainThread() |
|
|
|
=> mainThread = Thread.CurrentThread; |
|
|
@ -120,9 +129,9 @@ namespace IPA.Utilities |
|
|
|
/// This only gives a
|
|
|
|
/// </remarks>
|
|
|
|
/// <value>the type of release this is</value>
|
|
|
|
public static Release ReleaseType => (_releaseCache ?? (_releaseCache = CheckIsSteam() ? Release.Steam : Release.Other)).Value; |
|
|
|
public static Release ReleaseType => _releaseCache ??= CheckIsSteam() ? Release.Steam : Release.Other; |
|
|
|
|
|
|
|
private static string _installRoot; |
|
|
|
private static string? _installRoot; |
|
|
|
/// <summary>
|
|
|
|
/// Gets the path to the game's install directory.
|
|
|
|
/// </summary>
|
|
|
@ -165,4 +174,59 @@ namespace IPA.Utilities |
|
|
|
&& installDirInfo.Parent?.Parent?.Name == "steamapps"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// An awaitable which, when awaited, switches the current context to the Unity main thread.
|
|
|
|
/// </summary>
|
|
|
|
/// <seealso cref="UnityGame.SwitchToMainThreadAsync"/>
|
|
|
|
[SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", |
|
|
|
Justification = "This type should never be compared.")] |
|
|
|
public struct SwitchToUnityMainThreadAwaitable |
|
|
|
{ |
|
|
|
/// <summary>
|
|
|
|
/// Gets the awaiter for this awaitable.
|
|
|
|
/// </summary>
|
|
|
|
/// <returns>The awaiter for this awaitable.</returns>
|
|
|
|
public SwitchToUnityMainThreadAwaiter GetAwaiter() => default; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// An awaiter which, when awaited, switches the current context to the Unity main thread.
|
|
|
|
/// </summary>
|
|
|
|
/// <seealso cref="UnityGame.SwitchToMainThreadAsync"/>
|
|
|
|
[SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", |
|
|
|
Justification = "This type should never be compared.")] |
|
|
|
public struct SwitchToUnityMainThreadAwaiter : INotifyCompletion, ICriticalNotifyCompletion |
|
|
|
{ |
|
|
|
private static readonly ContextCallback InvokeAction = static o => ((Action)o!)(); |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets whether or not this awaiter is completed.
|
|
|
|
/// </summary>
|
|
|
|
public bool IsCompleted => UnityGame.OnMainThread; |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Gets the result of this awaiter.
|
|
|
|
/// </summary>
|
|
|
|
public void GetResult() { } |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Registers a continuation to be called when this awaiter finishes.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="continuation">The continuation.</param>
|
|
|
|
public void OnCompleted(Action continuation) |
|
|
|
{ |
|
|
|
var ec = ExecutionContext.Capture(); |
|
|
|
UnityMainThreadTaskScheduler.Default.QueueAction(() => ExecutionContext.Run(ec, InvokeAction, continuation)); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Registers a continuation to be called when this awaiter finishes, without capturing the execution context.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="continuation">The continuation.</param>
|
|
|
|
public void UnsafeOnCompleted(Action continuation) |
|
|
|
{ |
|
|
|
UnityMainThreadTaskScheduler.Default.QueueAction(continuation); |
|
|
|
} |
|
|
|
} |
|
|
|
} |