mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-17 13:27:43 +01:00
merge master into profiles
This commit is contained in:
commit
fe6196d0ad
57 changed files with 1118 additions and 287 deletions
60
Dalamud/Utility/AsyncUtils.cs
Normal file
60
Dalamud/Utility/AsyncUtils.cs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Dalamud.Utility;
|
||||
|
||||
/// <summary>
|
||||
/// A set of utilities around and for better asynchronous behavior.
|
||||
/// </summary>
|
||||
public static class AsyncUtils
|
||||
{
|
||||
/// <summary>
|
||||
/// Race a set of tasks, returning either the first to succeed or an aggregate of all exceptions. This helper does
|
||||
/// not perform any automatic cancellation of losing tasks, nor does it handle exceptions of losing tasks.
|
||||
/// </summary>
|
||||
/// <remarks>Derived from <a href="https://stackoverflow.com/a/37529395">this StackOverflow post</a>.</remarks>
|
||||
/// <param name="tasks">A list of tasks to race.</param>
|
||||
/// <typeparam name="T">The return type of all raced tasks.</typeparam>
|
||||
/// <exception cref="AggregateException">Thrown when all tasks given to this method fail.</exception>
|
||||
/// <returns>Returns the first task that completes, according to <see cref="Task{TResult}.IsCompletedSuccessfully"/>.</returns>
|
||||
public static Task<T> FirstSuccessfulTask<T>(ICollection<Task<T>> tasks)
|
||||
{
|
||||
var tcs = new TaskCompletionSource<T>();
|
||||
var remainingTasks = tasks.Count;
|
||||
|
||||
foreach (var task in tasks)
|
||||
{
|
||||
task.ContinueWith(t =>
|
||||
{
|
||||
if (t.IsCompletedSuccessfully)
|
||||
{
|
||||
tcs.TrySetResult(t.Result);
|
||||
}
|
||||
else if (Interlocked.Decrement(ref remainingTasks) == 0)
|
||||
{
|
||||
tcs.SetException(new AggregateException(tasks.SelectMany(f => f.Exception?.InnerExceptions)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provide a <see cref="Task.Delay(int, CancellationToken)"/> that won't throw an exception when it's canceled.
|
||||
/// </summary>
|
||||
/// <inheritdoc cref="Task.Delay(int, CancellationToken)"/>
|
||||
public static async Task CancellableDelay(int millisecondsDelay, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(millisecondsDelay, cancellationToken);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ using Dalamud.Game;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Utility.Signatures.Wrappers;
|
||||
using Serilog;
|
||||
|
||||
namespace Dalamud.Utility.Signatures;
|
||||
|
||||
|
|
@ -151,7 +152,7 @@ public static class SignatureHelper
|
|||
var ctor = actualType.GetConstructor(new[] { typeof(IntPtr), hookDelegateType });
|
||||
if (ctor == null)
|
||||
{
|
||||
PluginLog.Error("Error in SignatureHelper: could not find Hook constructor");
|
||||
Log.Error("Error in SignatureHelper: could not find Hook constructor");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using Dalamud.Game.ClientState.Objects.Types;
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Colors;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Networking.Http;
|
||||
using ImGuiNET;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Microsoft.Win32;
|
||||
|
|
@ -40,7 +41,8 @@ public static class Util
|
|||
/// Gets an httpclient for usage.
|
||||
/// Do NOT await this.
|
||||
/// </summary>
|
||||
public static HttpClient HttpClient { get; } = new();
|
||||
[Obsolete($"Use Service<{nameof(HappyHttpClient)}> instead.")]
|
||||
public static HttpClient HttpClient { get; } = Service<HappyHttpClient>.Get().SharedHttpClient;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly version of Dalamud.
|
||||
|
|
@ -556,6 +558,56 @@ public static class Util
|
|||
Process.Start(process);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Perform a "zipper merge" (A, 1, B, 2, C, 3) of multiple enumerables, allowing for lists to end early.
|
||||
/// </summary>
|
||||
/// <param name="sources">A set of enumerable sources to combine.</param>
|
||||
/// <typeparam name="TSource">The resulting type of the merged list to return.</typeparam>
|
||||
/// <returns>A new enumerable, consisting of the final merge of all lists.</returns>
|
||||
public static IEnumerable<TSource> ZipperMerge<TSource>(params IEnumerable<TSource>[] sources)
|
||||
{
|
||||
// Borrowed from https://codereview.stackexchange.com/a/263451, thank you!
|
||||
var enumerators = new IEnumerator<TSource>[sources.Length];
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < sources.Length; i++)
|
||||
{
|
||||
enumerators[i] = sources[i].GetEnumerator();
|
||||
}
|
||||
|
||||
var hasNext = new bool[enumerators.Length];
|
||||
|
||||
bool MoveNext()
|
||||
{
|
||||
var anyHasNext = false;
|
||||
for (var i = 0; i < enumerators.Length; i++)
|
||||
{
|
||||
anyHasNext |= hasNext[i] = enumerators[i].MoveNext();
|
||||
}
|
||||
|
||||
return anyHasNext;
|
||||
}
|
||||
|
||||
while (MoveNext())
|
||||
{
|
||||
for (var i = 0; i < enumerators.Length; i++)
|
||||
{
|
||||
if (hasNext[i])
|
||||
{
|
||||
yield return enumerators[i].Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var enumerator in enumerators)
|
||||
{
|
||||
enumerator?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispose this object.
|
||||
/// </summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue