mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 10:17:22 +01:00
Add IFramework (#1286)
This commit is contained in:
parent
342e1bc06c
commit
385c4b7a8b
3 changed files with 150 additions and 87 deletions
|
|
@ -12,6 +12,7 @@ using Dalamud.Game.Gui.Toast;
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility;
|
||||
using Serilog;
|
||||
|
||||
|
|
@ -23,7 +24,10 @@ namespace Dalamud.Game;
|
|||
[PluginInterface]
|
||||
[InterfaceVersion("1.0")]
|
||||
[ServiceManager.BlockingEarlyLoadedService]
|
||||
public sealed class Framework : IDisposable, IServiceType
|
||||
#pragma warning disable SA1015
|
||||
[ResolveVia<IFramework>]
|
||||
#pragma warning restore SA1015
|
||||
public sealed class Framework : IDisposable, IServiceType, IFramework
|
||||
{
|
||||
private static readonly Stopwatch StatsStopwatch = new();
|
||||
|
||||
|
|
@ -57,12 +61,6 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
this.destroyHook = Hook<OnRealDestroyDelegate>.FromAddress(this.Address.DestroyAddress, this.HandleFrameworkDestroy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="Update"/> event.
|
||||
/// </summary>
|
||||
/// <param name="framework">The Framework instance.</param>
|
||||
public delegate void OnUpdateDelegate(Framework framework);
|
||||
|
||||
/// <summary>
|
||||
/// A delegate type used during the native Framework::destroy.
|
||||
/// </summary>
|
||||
|
|
@ -81,10 +79,8 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
|
||||
private delegate IntPtr OnDestroyDetour(); // OnDestroyDelegate
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired every time the game framework updates.
|
||||
/// </summary>
|
||||
public event OnUpdateDelegate Update;
|
||||
/// <inheritdoc/>
|
||||
public event IFramework.OnUpdateDelegate Update;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the collection of stats is enabled.
|
||||
|
|
@ -96,34 +92,22 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
public static Dictionary<string, List<double>> StatsHistory { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a raw pointer to the instance of Client::Framework.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public FrameworkAddressResolver Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time that the Framework Update event was triggered.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastUpdate { get; private set; } = DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time in UTC that the Framework Update event was triggered.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public DateTime LastUpdateUTC { get; private set; } = DateTime.MinValue;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the delta between the last Framework Update and the currently executing one.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public TimeSpan UpdateDelta { get; private set; } = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether currently executing code is running in the game's framework update thread.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public bool IsInFrameworkUpdateThread => Thread.CurrentThread == this.frameworkUpdateThread;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether game Framework is unloading.
|
||||
/// </summary>
|
||||
/// <inheritdoc/>
|
||||
public bool IsFrameworkUnloading { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -131,20 +115,11 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
internal bool DispatchUpdateEvents { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnFrameworkThread<T>(Func<T> func) =>
|
||||
this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading ? Task.FromResult(func()) : this.RunOnTick(func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <param name="action">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnFrameworkThread(Action action)
|
||||
{
|
||||
if (this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading)
|
||||
|
|
@ -165,32 +140,15 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnFrameworkThread<T>(Func<Task<T>> func) =>
|
||||
this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading ? func() : this.RunOnTick(func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnFrameworkThread(Func<Task> func) =>
|
||||
this.IsInFrameworkUpdateThread || this.IsFrameworkUnloading ? func() : this.RunOnTick(func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnTick<T>(Func<T> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
@ -219,14 +177,7 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <param name="action">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnTick(Action action, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
@ -255,15 +206,7 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
return tcs.Task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task<T> RunOnTick<T>(Func<Task<T>> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
@ -292,14 +235,7 @@ public sealed class Framework : IDisposable, IServiceType
|
|||
return tcs.Task.ContinueWith(x => x.Result, cancellationToken).Unwrap();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
/// <inheritdoc/>
|
||||
public Task RunOnTick(Func<Task> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (this.IsFrameworkUnloading)
|
||||
|
|
|
|||
126
Dalamud/Plugin/Services/IFramework.cs
Normal file
126
Dalamud/Plugin/Services/IFramework.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Dalamud.Game;
|
||||
|
||||
namespace Dalamud.Plugin.Services;
|
||||
|
||||
/// <summary>
|
||||
/// This class represents the Framework of the native game client and grants access to various subsystems.
|
||||
/// </summary>
|
||||
public interface IFramework
|
||||
{
|
||||
/// <summary>
|
||||
/// A delegate type used with the <see cref="Update"/> event.
|
||||
/// </summary>
|
||||
/// <param name="framework">The Framework instance.</param>
|
||||
public delegate void OnUpdateDelegate(Framework framework);
|
||||
|
||||
/// <summary>
|
||||
/// Event that gets fired every time the game framework updates.
|
||||
/// </summary>
|
||||
public event OnUpdateDelegate Update;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a raw pointer to the instance of Client::Framework.
|
||||
/// </summary>
|
||||
public FrameworkAddressResolver Address { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time that the Framework Update event was triggered.
|
||||
/// </summary>
|
||||
public DateTime LastUpdate { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the last time in UTC that the Framework Update event was triggered.
|
||||
/// </summary>
|
||||
public DateTime LastUpdateUTC { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the delta between the last Framework Update and the currently executing one.
|
||||
/// </summary>
|
||||
public TimeSpan UpdateDelta { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether currently executing code is running in the game's framework update thread.
|
||||
/// </summary>
|
||||
public bool IsInFrameworkUpdateThread { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether game Framework is unloading.
|
||||
/// </summary>
|
||||
public bool IsFrameworkUnloading { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
public Task<T> RunOnFrameworkThread<T>(Func<T> func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <param name="action">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
public Task RunOnFrameworkThread(Action action);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
public Task<T> RunOnFrameworkThread<T>(Func<Task<T>> func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function right away if this function has been called from game's Framework.Update thread, or otherwise run on next Framework.Update call.
|
||||
/// </summary>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <returns>Task representing the pending or already completed function.</returns>
|
||||
public Task RunOnFrameworkThread(Func<Task> func);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
public Task<T> RunOnTick<T>(Func<T> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <param name="action">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
public Task RunOnTick(Action action, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Return type.</typeparam>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
public Task<T> RunOnTick<T>(Func<Task<T>> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Run given function in upcoming Framework.Tick call.
|
||||
/// </summary>
|
||||
/// <param name="func">Function to call.</param>
|
||||
/// <param name="delay">Wait for given timespan before calling this function.</param>
|
||||
/// <param name="delayTicks">Count given number of Framework.Tick calls before calling this function. This takes precedence over delay parameter.</param>
|
||||
/// <param name="cancellationToken">Cancellation token which will prevent the execution of this function if wait conditions are not met.</param>
|
||||
/// <returns>Task representing the pending function.</returns>
|
||||
public Task RunOnTick(Func<Task> func, TimeSpan delay = default, int delayTicks = default, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Linq;
|
||||
|
||||
using Dalamud.Game;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Serilog;
|
||||
|
||||
using static Dalamud.Game.Framework;
|
||||
|
|
@ -72,12 +73,12 @@ internal static class EventHandlerExtensions
|
|||
/// </summary>
|
||||
/// <param name="updateDelegate">The OnUpdateDelegate in question.</param>
|
||||
/// <param name="framework">Framework to be passed on to OnUpdateDelegate.</param>
|
||||
public static void InvokeSafely(this OnUpdateDelegate updateDelegate, Framework framework)
|
||||
public static void InvokeSafely(this IFramework.OnUpdateDelegate updateDelegate, Framework framework)
|
||||
{
|
||||
if (updateDelegate == null)
|
||||
return;
|
||||
|
||||
foreach (var action in updateDelegate.GetInvocationList().Cast<OnUpdateDelegate>())
|
||||
foreach (var action in updateDelegate.GetInvocationList().Cast<IFramework.OnUpdateDelegate>())
|
||||
{
|
||||
HandleInvoke(() => action(framework));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue