mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-07-24 12:06:34 +00:00
* Bump version to 0.9.10.1 * Bump Microsoft.Web.WebView2 from 1.0.3719.77 to 1.0.3800.47 (#1442) --- updated-dependencies: - dependency-name: Microsoft.Web.WebView2 dependency-version: 1.0.3800.47 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Improve mod view responsiveness (#1443) * Improve application launcher logging (Closes #1441) (#1444) * Damage modifier 0x248 (Closes #1438) (#1445) * Initial commit * Setup generator * Progress * Update generator * Initial commit * Setup generator * Progress * Update generator * Fix library loading * Move code to gwca * Fix leave party * Disable console on Release * Add more exports to gwca * Upgrade gwca * Fixes to character selector * Fix GetWindowHandle * Move character selector to frame based * Fix config spamming --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Alexandru Macocian <amacocian@microsoft.com>
93 lines
2.7 KiB
C#
93 lines
2.7 KiB
C#
using Daybreak.API.Interop;
|
|
using Daybreak.API.Models;
|
|
using System.Collections.Concurrent;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
|
|
namespace Daybreak.API.Services.Interop;
|
|
|
|
public sealed class GameThreadService
|
|
{
|
|
[SuppressUnmanagedCodeSecurity]
|
|
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
|
private delegate void GameThreadCallback();
|
|
|
|
// Prevent GC of delegates passed to native code
|
|
private readonly ConcurrentDictionary<GameThreadCallback, bool> prevent_GC_callbacks = [];
|
|
|
|
public Task QueueOnGameThread(Action action, CancellationToken cancellationToken)
|
|
{
|
|
var taskCompletionSource = new TaskCompletionSource();
|
|
var item = new WorkItem(action, taskCompletionSource, cancellationToken);
|
|
|
|
GameThreadCallback callback = null!;
|
|
callback = () =>
|
|
{
|
|
try
|
|
{
|
|
if (item.CancellationToken.IsCancellationRequested)
|
|
{
|
|
item.Cancel();
|
|
return;
|
|
}
|
|
|
|
item.Execute();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
item.Exception(ex);
|
|
}
|
|
finally
|
|
{
|
|
this.prevent_GC_callbacks.TryRemove(callback, out _);
|
|
}
|
|
};
|
|
|
|
// CRITICAL: Keep delegate alive until callback executes
|
|
this.prevent_GC_callbacks[callback] = true;
|
|
|
|
var funcPtr = Marshal.GetFunctionPointerForDelegate(callback);
|
|
GWCA.GW.GameThread.Enqueue(funcPtr, false);
|
|
|
|
return taskCompletionSource.Task;
|
|
}
|
|
|
|
public Task<T> QueueOnGameThread<T>(Func<T> action, CancellationToken cancellationToken)
|
|
{
|
|
var taskCompletionSource = new TaskCompletionSource<T>();
|
|
var item = new WorkItem<T>(action, taskCompletionSource, cancellationToken);
|
|
|
|
GameThreadCallback callback = null!;
|
|
callback = () =>
|
|
{
|
|
try
|
|
{
|
|
if (item.CancellationToken.IsCancellationRequested)
|
|
{
|
|
item.Cancel();
|
|
return;
|
|
}
|
|
|
|
item.Execute();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
item.Exception(ex);
|
|
}
|
|
finally
|
|
{
|
|
// Remove from prevent-GC set after execution
|
|
this.prevent_GC_callbacks.TryRemove(callback, out _);
|
|
}
|
|
};
|
|
|
|
// CRITICAL: Keep delegate alive until callback executes
|
|
this.prevent_GC_callbacks[callback] = true;
|
|
|
|
var funcPtr = Marshal.GetFunctionPointerForDelegate(callback);
|
|
GWCA.GW.GameThread.Enqueue(funcPtr, false);
|
|
|
|
return taskCompletionSource.Task;
|
|
}
|
|
}
|