This commit is contained in:
Anna 2022-09-03 19:45:16 -04:00
parent c827a5f570
commit 72d60a2bb5
4 changed files with 188 additions and 1 deletions

19
client/Message.cs Normal file
View File

@ -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; }
}

69
client/Messages.cs Normal file
View File

@ -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<Message> 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<Message[]>(json)!;
foreach (var message in messages) {
this.SpawnQueue.Enqueue(message);
}
});
}
private void RemoveVfx(object? sender, EventArgs? e) {
this.Plugin.Vfx.RemoveAll();
}
}

View File

@ -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();
}

90
client/Vfx.cs Normal file
View File

@ -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<byte*, byte*, VfxStruct*> _staticVfxCreate;
[Signature("E8 ?? ?? ?? ?? 8B 4B 7C 85 C9")]
private delegate* unmanaged<VfxStruct*, float, uint, void> _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<VfxStruct*, void> _staticVfxRemove;
private List<IntPtr> 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;
}
}