From 799700c985b85fa6629d8d15833a1600653136c1 Mon Sep 17 00:00:00 2001 From: Anna Clemens Date: Sat, 3 Sep 2022 19:45:16 -0400 Subject: [PATCH] uwu --- client/Message.cs | 19 ++++++++++ client/Messages.cs | 69 +++++++++++++++++++++++++++++++++++ client/Plugin.cs | 11 +++++- client/Vfx.cs | 90 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 client/Message.cs create mode 100644 client/Messages.cs create mode 100644 client/Vfx.cs diff --git a/client/Message.cs b/client/Message.cs new file mode 100644 index 0000000..67722d4 --- /dev/null +++ b/client/Message.cs @@ -0,0 +1,19 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace OrangeGuidanceTomestone; + +[Serializable] +[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +internal class Message { + public Guid Id { get; init; } + public float X { get; init; } + public float Y { get; init; } + public float Z { get; init; } + + [JsonProperty("message")] + public string Text { get; init; } + + public int PositiveVotes { get; init; } + public int NegativeVotes { get; init; } +} diff --git a/client/Messages.cs b/client/Messages.cs new file mode 100644 index 0000000..15e2ddf --- /dev/null +++ b/client/Messages.cs @@ -0,0 +1,69 @@ +using System.Numerics; +using Dalamud.Game; +using Newtonsoft.Json; + +namespace OrangeGuidanceTomestone; + +internal class Messages : IDisposable { + private const string VfxPath = "bg/ffxiv/fst_f1/common/vfx/eff/b0941trp1d_o.avfx"; + + private Plugin Plugin { get; } + + private Queue SpawnQueue { get; } = new(); + + internal Messages(Plugin plugin) { + this.Plugin = plugin; + + this.SpawnVfx(); + + this.Plugin.Framework.Update += this.HandleSpawnQueue; + this.Plugin.ClientState.Login += this.SpawnVfx; + this.Plugin.ClientState.Logout += this.RemoveVfx; + this.Plugin.ClientState.TerritoryChanged += this.SpawnVfx; + } + + public void Dispose() { + this.Plugin.ClientState.TerritoryChanged -= this.SpawnVfx; + this.Plugin.ClientState.Logout -= this.RemoveVfx; + this.Plugin.ClientState.Login -= this.SpawnVfx; + this.Plugin.Framework.Update -= this.HandleSpawnQueue; + } + + private unsafe void HandleSpawnQueue(Framework framework) { + if (!this.SpawnQueue.TryDequeue(out var message)) { + return; + } + + this.Plugin.Vfx.SpawnStatic(VfxPath, new Vector3(message.X, message.Y, message.Z)); + } + + private void SpawnVfx(object? sender, EventArgs e) { + this.SpawnVfx(); + } + + private void SpawnVfx(object? sender, ushort e) { + this.SpawnVfx(); + } + + private void SpawnVfx() { + var territory = this.Plugin.ClientState.TerritoryType; + if (territory == 0) { + return; + } + + this.RemoveVfx(null, null); + + Task.Run(async () => { + var resp = await new HttpClient().GetAsync($"https://tryfingerbuthole.anna.lgbt/messages/{territory}"); + var json = await resp.Content.ReadAsStringAsync(); + var messages = JsonConvert.DeserializeObject(json)!; + foreach (var message in messages) { + this.SpawnQueue.Enqueue(message); + } + }); + } + + private void RemoveVfx(object? sender, EventArgs? e) { + this.Plugin.Vfx.RemoveAll(); + } +} diff --git a/client/Plugin.cs b/client/Plugin.cs index 7c55577..afd1b07 100644 --- a/client/Plugin.cs +++ b/client/Plugin.cs @@ -1,4 +1,5 @@ -using Dalamud.Game.ClientState; +using Dalamud.Game; +using Dalamud.Game.ClientState; using Dalamud.IoC; using Dalamud.Plugin; @@ -13,8 +14,13 @@ public class Plugin : IDalamudPlugin { [PluginService] internal ClientState ClientState { get; init; } + [PluginService] + internal Framework Framework { get; init; } + internal Configuration Config { get; } + internal Vfx Vfx { get; } internal PluginUi Ui { get; } + internal Messages Messages { get; } public Plugin() { this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration(); @@ -27,10 +33,13 @@ public class Plugin : IDalamudPlugin { }); } + this.Vfx = new Vfx(); this.Ui = new PluginUi(this); + this.Messages = new Messages(this); } public void Dispose() { + this.Messages.Dispose(); this.Ui.Dispose(); } diff --git a/client/Vfx.cs b/client/Vfx.cs new file mode 100644 index 0000000..00b15a8 --- /dev/null +++ b/client/Vfx.cs @@ -0,0 +1,90 @@ +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text; +using Dalamud.Utility.Signatures; + +namespace OrangeGuidanceTomestone; + +internal unsafe class Vfx : IDisposable { + private static readonly byte[] Pool = Encoding.UTF8.GetBytes("Client.System.Scheduler.Instance.VfxObject"); + + [Signature("E8 ?? ?? ?? ?? F3 0F 10 35 ?? ?? ?? ?? 48 89 43 08")] + private delegate* unmanaged _staticVfxCreate; + + [Signature("E8 ?? ?? ?? ?? 8B 4B 7C 85 C9")] + private delegate* unmanaged _staticVfxRun; + + [Signature("40 53 48 83 EC 20 48 8B D9 48 8B 89 ?? ?? ?? ?? 48 85 C9 74 28 33 D2 E8 ?? ?? ?? ?? 48 8B 8B ?? ?? ?? ?? 48 85 C9")] + private delegate* unmanaged _staticVfxRemove; + + private List Spawned { get; } = new(); + + internal Vfx() { + SignatureHelper.Initialise(this); + } + + public void Dispose() { + this.RemoveAll(); + } + + internal void RemoveAll() { + foreach (var spawned in this.Spawned) { + this.RemoveStatic((VfxStruct*) spawned); + } + + this.Spawned.Clear(); + } + + internal VfxStruct* SpawnStatic(string path, Vector3 pos) { + VfxStruct* vfx; + fixed (byte* p = Encoding.UTF8.GetBytes(path)) { + fixed (byte* pool = Pool) { + vfx = this._staticVfxCreate(p, pool); + } + } + + if (vfx == null) { + return null; + } + + this._staticVfxRun(vfx, 0.0f, 0xFFFFFFFF); + + // update position + vfx->Position = new Vector3(pos.X, pos.Y, pos.Z); + + // update + vfx->Flags |= 2; + + this.Spawned.Add((IntPtr) vfx); + + return vfx; + } + + internal void RemoveStatic(VfxStruct* vfx) { + this._staticVfxRemove(vfx); + } + + [StructLayout(LayoutKind.Explicit)] + internal struct VfxStruct { + [FieldOffset(0x38)] + public byte Flags; + + [FieldOffset(0x50)] + public Vector3 Position; + + [FieldOffset(0x70)] + public Vector3 Scale; + + [FieldOffset(0x128)] + public int ActorCaster; + + [FieldOffset(0x130)] + public int ActorTarget; + + [FieldOffset(0x1B8)] + public int StaticCaster; + + [FieldOffset(0x1C0)] + public int StaticTarget; + } +}