diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs
index 58660ab09..4f8b7e6b4 100644
--- a/Dalamud/Dalamud.cs
+++ b/Dalamud/Dalamud.cs
@@ -143,6 +143,8 @@ namespace Dalamud {
private readonly ManualResetEvent unloadSignal;
+ private readonly ManualResetEvent finishUnloadSignal;
+
private readonly string baseDirectory;
#endregion
@@ -162,13 +164,14 @@ namespace Dalamud {
///
internal DirectoryInfo AssetDirectory => new DirectoryInfo(this.StartInfo.AssetDirectory);
- public Dalamud(DalamudStartInfo info, LoggingLevelSwitch loggingLevelSwitch) {
+ public Dalamud(DalamudStartInfo info, LoggingLevelSwitch loggingLevelSwitch, ManualResetEvent finishSignal) {
this.StartInfo = info;
this.LogLevelSwitch = loggingLevelSwitch;
this.baseDirectory = info.WorkingDirectory;
this.unloadSignal = new ManualResetEvent(false);
+ this.finishUnloadSignal = finishSignal;
this.Configuration = DalamudConfiguration.Load(info.ConfigurationPath);
@@ -277,6 +280,10 @@ namespace Dalamud {
this.unloadSignal.WaitOne();
}
+ public void WaitForUnloadFinish() {
+ this.finishUnloadSignal.WaitOne();
+ }
+
public void Dispose() {
// this must be done before unloading plugins, or it can cause a race condition
// due to rendering happening on another thread, where a plugin might receive
@@ -305,6 +312,8 @@ namespace Dalamud {
this.Data.Dispose();
this.AntiDebug?.Dispose();
+
+ Log.Debug("Dalamud::Dispose OK!");
}
internal void ReplaceExceptionHandler() {
diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs
index dfeb8f866..a64430644 100644
--- a/Dalamud/EntryPoint.cs
+++ b/Dalamud/EntryPoint.cs
@@ -1,6 +1,7 @@
using System;
using System.IO;
using System.Net;
+using System.Threading;
using System.Threading.Tasks;
using Dalamud.Interface;
using EasyHook;
@@ -19,6 +20,8 @@ namespace Dalamud {
var (logger, levelSwitch) = NewLogger(info.WorkingDirectory);
Log.Logger = logger;
+ var finishSignal = new ManualResetEvent(false);
+
try {
Log.Information(new string('-', 200));
Log.Information("Initializing a session..");
@@ -31,7 +34,7 @@ namespace Dalamud {
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
- using var dalamud = new Dalamud(info, levelSwitch);
+ using var dalamud = new Dalamud(info, levelSwitch, finishSignal);
Log.Information("Starting a session..");
// Run session
@@ -44,6 +47,8 @@ namespace Dalamud {
Log.Information("Session has ended.");
Log.CloseAndFlush();
+
+ finishSignal.Set();
}
}
diff --git a/Dalamud/Game/Internal/Framework.cs b/Dalamud/Game/Internal/Framework.cs
index e55f502ee..819b7945d 100644
--- a/Dalamud/Game/Internal/Framework.cs
+++ b/Dalamud/Game/Internal/Framework.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
+using System.Threading;
using Dalamud.Game.Internal.Gui;
using Dalamud.Game.Internal.Libc;
using Dalamud.Game.Internal.Network;
@@ -14,18 +15,25 @@ namespace Dalamud.Game.Internal {
/// This class represents the Framework of the native game client and grants access to various subsystems.
///
public sealed class Framework : IDisposable {
+ private readonly Dalamud dalamud;
+
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
private delegate bool OnUpdateDetour(IntPtr framework);
+ private delegate IntPtr OnDestroyDetour();
+
public delegate void OnUpdateDelegate(Framework framework);
+ public delegate IntPtr OnDestroyDelegate();
+
///
/// Event that gets fired every time the game framework updates.
///
public event OnUpdateDelegate OnUpdateEvent;
private Hook updateHook;
-
+
+ private Hook destroyHook;
///
/// A raw pointer to the instance of Client::Framework
@@ -56,6 +64,7 @@ namespace Dalamud.Game.Internal {
#endregion
public Framework(SigScanner scanner, Dalamud dalamud) {
+ this.dalamud = dalamud;
Address = new FrameworkAddressResolver();
Address.Setup(scanner);
@@ -74,7 +83,8 @@ namespace Dalamud.Game.Internal {
Network = new GameNetwork(scanner);
- //Resource = new ResourceManager(dalamud, scanner);
+ this.destroyHook =
+ new Hook(Address.OnDestroy, new OnDestroyDelegate(HandleFrameworkDestroy), this);
}
private void HookVTable() {
@@ -93,9 +103,9 @@ namespace Dalamud.Game.Internal {
public void Enable() {
Gui.Enable();
Network.Enable();
- //Resource.Enable();
this.updateHook.Enable();
+ this.destroyHook.Enable();
}
public void Dispose() {
@@ -150,5 +160,14 @@ namespace Dalamud.Game.Internal {
return this.updateHook.Original(framework);
}
+
+ private IntPtr HandleFrameworkDestroy() {
+ Log.Information("Framework::OnDestroy!");
+ this.dalamud.Unload();
+
+ this.dalamud.WaitForUnloadFinish();
+
+ return this.destroyHook.Original();
+ }
}
}
diff --git a/Dalamud/Game/Internal/FrameworkAddressResolver.cs b/Dalamud/Game/Internal/FrameworkAddressResolver.cs
index 6d6b11263..6d130beac 100644
--- a/Dalamud/Game/Internal/FrameworkAddressResolver.cs
+++ b/Dalamud/Game/Internal/FrameworkAddressResolver.cs
@@ -8,6 +8,8 @@ namespace Dalamud.Game.Internal {
public IntPtr GuiManager { get; private set; }
public IntPtr ScriptManager { get; private set; }
+
+ public IntPtr OnDestroy { get; private set; }
protected override void Setup64Bit(SigScanner sig) {
@@ -19,6 +21,8 @@ namespace Dalamud.Game.Internal {
// Called from Framework::Init
ScriptManager = BaseAddress + 0x2C68; // note that no deref here
+
+ OnDestroy = sig.ScanText("48 83 EC 48 48 8B 0D ?? ?? ?? ?? 48 85 C9");
}
private void SetupFramework(SigScanner scanner) {