feat: add toast queue and event

This commit is contained in:
Anna Clemens 2021-04-06 06:23:13 -04:00
parent 94d27b2428
commit 5845af4fe3
No known key found for this signature in database
GPG key ID: 0B391D8F06FCD9E0
3 changed files with 90 additions and 12 deletions

View file

@ -120,6 +120,7 @@ namespace Dalamud.Game.Internal {
private bool HandleFrameworkUpdate(IntPtr framework) {
try {
Gui.Chat.UpdateQueue(this);
Gui.Toast.UpdateQueue();
Network.UpdateQueue(this);
} catch (Exception ex) {
Log.Error(ex, "Exception while handling Framework::Update hook.");

View file

@ -452,6 +452,7 @@ namespace Dalamud.Game.Internal.Gui {
public void Enable() {
Chat.Enable();
Toast.Enable();
PartyFinder.Enable();
this.setGlobalBgmHook.Enable();
this.handleItemHoverHook.Enable();
@ -463,6 +464,7 @@ namespace Dalamud.Game.Internal.Gui {
public void Dispose() {
Chat.Dispose();
Toast.Dispose();
PartyFinder.Dispose();
this.setGlobalBgmHook.Dispose();
this.handleItemHoverHook.Dispose();

View file

@ -1,28 +1,60 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Dalamud.Game.Text.SeStringHandling;
using Dalamud.Hooking;
namespace Dalamud.Game.Internal.Gui
{
public class ToastGui
public class ToastGui : IDisposable
{
#region Events
public delegate void OnToastDelegate(ref SeString message, ref bool isHandled);
/// <summary>
/// Event that will be fired when a toast is sent by the game or a plugin.
/// </summary>
public event OnToastDelegate OnToast;
#endregion
#region Hooks
private readonly Hook<ShowToastDelegate> showToastHook;
#endregion
private delegate IntPtr ShowToastDelegate(IntPtr manager, IntPtr text, int layer, byte bool1, byte bool2, int logMessageId);
private Dalamud Dalamud { get; }
private ToastGuiAddressResolver Address { get; }
private delegate IntPtr ShowToastDelegate(IntPtr manager, IntPtr text, int layer, byte bool1, byte bool2, int logMessageId);
private Queue<byte[]> ToastQueue { get; } = new Queue<byte[]>();
private readonly ShowToastDelegate showToast;
public ToastGui(SigScanner scanner, Dalamud dalamud)
{
Dalamud = dalamud;
this.Dalamud = dalamud;
Address = new ToastGuiAddressResolver();
Address.Setup(scanner);
this.Address = new ToastGuiAddressResolver();
this.Address.Setup(scanner);
this.showToast = Marshal.GetDelegateForFunctionPointer<ShowToastDelegate>(Address.ShowToast);
Marshal.GetDelegateForFunctionPointer<ShowToastDelegate>(this.Address.ShowToast);
this.showToastHook = new Hook<ShowToastDelegate>(this.Address.ShowToast, new ShowToastDelegate(this.HandleToastDetour));
}
public void Enable()
{
this.showToastHook.Enable();
}
public void Dispose()
{
this.showToastHook.Dispose();
}
/// <summary>
@ -31,7 +63,7 @@ namespace Dalamud.Game.Internal.Gui
/// <param name="message">The message to be shown</param>
public void Show(string message)
{
this.Show(Encoding.UTF8.GetBytes(message));
this.ToastQueue.Enqueue(Encoding.UTF8.GetBytes(message));
}
/// <summary>
@ -40,20 +72,63 @@ namespace Dalamud.Game.Internal.Gui
/// <param name="message">The message to be shown</param>
public void Show(SeString message)
{
this.Show(message.Encode());
this.ToastQueue.Enqueue(message.Encode());
}
/// <summary>
/// Process the toast queue.
/// </summary>
internal void UpdateQueue()
{
while (this.ToastQueue.Count > 0)
{
var message = this.ToastQueue.Dequeue();
this.Show(message);
}
}
private void Show(byte[] bytes)
{
var manager = Dalamud.Framework.Gui.GetUIModule();
var manager = this.Dalamud.Framework.Gui.GetUIModule();
// terminate the string
var terminated = new byte[bytes.Length + 1];
Array.Copy(bytes, 0, terminated, 0, bytes.Length);
terminated[^1] = 0;
unsafe
{
fixed (byte* ptr = bytes)
fixed (byte* ptr = terminated)
{
this.showToast(manager, (IntPtr) ptr, 5, 0, 1, 0);
this.HandleToastDetour(manager, (IntPtr)ptr, 5, 0, 1, 0);
}
}
}
private IntPtr HandleToastDetour(IntPtr manager, IntPtr text, int layer, byte bool1, byte bool2, int logMessageId)
{
// get the message as an sestring
var bytes = new List<byte>();
unsafe
{
var ptr = (byte*)text;
while (*ptr != 0)
{
bytes.Add(*ptr);
ptr += 1;
}
}
// call events
var isHandled = false;
var str = this.Dalamud.SeStringManager.Parse(bytes.ToArray());
this.OnToast?.Invoke(ref str, ref isHandled);
// do nothing if handled or show the toast
return isHandled
? IntPtr.Zero
: this.showToastHook.Original(manager, text, layer, bool1, bool2, logMessageId);
}
}
}