From ea4875c2970b2850a945d681a3ded6ef921f89f4 Mon Sep 17 00:00:00 2001 From: Anna Date: Sun, 4 Sep 2022 01:03:59 -0400 Subject: [PATCH] kk --- client/Commands.cs | 2 +- client/Helpers/ServerHelper.cs | 27 ++ client/Message.cs | 31 ++ client/Messages.cs | 10 +- client/PluginUi.cs | 397 +----------------------- client/Ui/MainWindow.cs | 46 +++ client/Ui/MainWindowTabs/ITab.cs | 6 + client/Ui/MainWindowTabs/MessageList.cs | 53 ++++ client/Ui/MainWindowTabs/Write.cs | 252 +++++++++++++++ client/Ui/Viewer.cs | 100 ++++++ client/Ui/ViewerButton.cs | 39 +++ server/src/message.rs | 2 +- server/src/pack.rs | 2 +- server/src/web.rs | 1 + server/src/web/write.rs | 2 +- 15 files changed, 575 insertions(+), 395 deletions(-) create mode 100644 client/Helpers/ServerHelper.cs create mode 100644 client/Ui/MainWindow.cs create mode 100644 client/Ui/MainWindowTabs/ITab.cs create mode 100644 client/Ui/MainWindowTabs/MessageList.cs create mode 100644 client/Ui/MainWindowTabs/Write.cs create mode 100644 client/Ui/Viewer.cs create mode 100644 client/Ui/ViewerButton.cs diff --git a/client/Commands.cs b/client/Commands.cs index 8d65ace..bad68e2 100644 --- a/client/Commands.cs +++ b/client/Commands.cs @@ -16,6 +16,6 @@ internal class Commands : IDisposable { } private void OnCommand(string command, string arguments) { - this.Plugin.Ui.WriterVisible ^= true; + this.Plugin.Ui.MainWindow.Visible ^= true; } } diff --git a/client/Helpers/ServerHelper.cs b/client/Helpers/ServerHelper.cs new file mode 100644 index 0000000..eb4a9fe --- /dev/null +++ b/client/Helpers/ServerHelper.cs @@ -0,0 +1,27 @@ +namespace OrangeGuidanceTomestone.Helpers; + +internal static class ServerHelper { + internal static HttpRequestMessage GetRequest(string apiKey, HttpMethod method, string tail, string? contentType = null, HttpContent? content = null) { + if (!tail.StartsWith('/')) { + tail = '/' + tail; + } + + var url = $"https://tryfingerbuthole.anna.lgbt{tail}"; + var req = new HttpRequestMessage(method, url); + if (content != null) { + req.Content = content; + } + + req.Headers.Add("X-Api-Key", apiKey); + if (contentType != null) { + req.Headers.Add("Content-Type", contentType); + } + + return req; + } + + internal static async Task SendRequest(string apiKey, HttpMethod method, string tail, string? contentType = null, HttpContent? content = null) { + var req = GetRequest(apiKey, method, tail, contentType, content); + return await new HttpClient().SendAsync(req, HttpCompletionOption.ResponseHeadersRead); + } +} diff --git a/client/Message.cs b/client/Message.cs index 77b9802..b1a7a7b 100644 --- a/client/Message.cs +++ b/client/Message.cs @@ -20,3 +20,34 @@ internal class Message { internal Vector3 Position => new(this.X, this.Y, this.Z); } + +[Serializable] +[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))] +internal class MessageWithTerritory { + public Guid Id { get; init; } + public uint Territory { 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; } + + internal Vector3 Position => new(this.X, this.Y, this.Z); + + internal static MessageWithTerritory From(Message message, uint territory) { + return new MessageWithTerritory { + Id = message.Id, + Territory = territory, + X = message.X, + Y = message.Y, + Z = message.Z, + Text = message.Text, + PositiveVotes = message.PositiveVotes, + NegativeVotes = message.NegativeVotes, + }; + } +} diff --git a/client/Messages.cs b/client/Messages.cs index 9e59abc..2b00ef0 100644 --- a/client/Messages.cs +++ b/client/Messages.cs @@ -2,6 +2,7 @@ using System.Numerics; using Dalamud.Game; using Dalamud.Logging; using Newtonsoft.Json; +using OrangeGuidanceTomestone.Helpers; namespace OrangeGuidanceTomestone; @@ -63,10 +64,11 @@ internal class Messages : IDisposable { this.RemoveVfx(null, null); Task.Run(async () => { - var req = new HttpRequestMessage(HttpMethod.Get, $"https://tryfingerbuthole.anna.lgbt/messages/{territory}"); - req.Headers.Add("X-Api-Key", this.Plugin.Config.ApiKey); - - var resp = await new HttpClient().SendAsync(req); + var resp = await ServerHelper.SendRequest( + this.Plugin.Config.ApiKey, + HttpMethod.Get, + $"/messages/{territory}" + ); var json = await resp.Content.ReadAsStringAsync(); var messages = JsonConvert.DeserializeObject(json)!; diff --git a/client/PluginUi.cs b/client/PluginUi.cs index b04bec4..784a6f1 100644 --- a/client/PluginUi.cs +++ b/client/PluginUi.cs @@ -1,30 +1,19 @@ -using System.Net.Http.Headers; -using System.Numerics; -using System.Text; -using Dalamud.Interface; -using ImGuiNET; -using Newtonsoft.Json; +using OrangeGuidanceTomestone.Ui; namespace OrangeGuidanceTomestone; public class PluginUi : IDisposable { private Plugin Plugin { get; } - internal bool WriterVisible; - internal bool ViewerVisible; - - private int _pack; - - private int _part1 = -1; - private (int, int) _word1 = (-1, -1); - - private int _part2 = -1; - private (int, int) _word2 = (-1, -1); - - private int _conj = -1; + internal MainWindow MainWindow { get; } + internal Viewer Viewer { get; } + internal ViewerButton ViewerButton { get; } internal PluginUi(Plugin plugin) { this.Plugin = plugin; + this.MainWindow = new MainWindow(this.Plugin); + this.Viewer = new Viewer(this.Plugin); + this.ViewerButton = new ViewerButton(this.Plugin); this.Plugin.Interface.UiBuilder.Draw += this.Draw; } @@ -34,374 +23,8 @@ public class PluginUi : IDisposable { } private void Draw() { - this.DrawWriter(); - this.DrawViewerButton(); - this.DrawViewer(); - } - - private void DrawWriter() { - if (!this.WriterVisible) { - return; - } - - if (!ImGui.Begin(this.Plugin.Name, ref this.WriterVisible)) { - ImGui.End(); - return; - } - - var packPrev = Pack.All.Value[this._pack].Name; - if (ImGui.BeginCombo("Pack", packPrev)) { - for (var i = 0; i < Pack.All.Value.Length; i++) { - var selPack = Pack.All.Value[i]; - if (!ImGui.Selectable(selPack.Name)) { - continue; - } - - this._pack = i; - - this._part1 = -1; - this._word1 = (-1, -1); - this._conj = -1; - this._part2 = -1; - this._word2 = (-1, -1); - } - - ImGui.EndCombo(); - } - - const string placeholder = "****"; - - void DrawPicker(string id, IReadOnlyList items, ref int x) { - var preview = x == -1 ? "" : items[x].Replace("{0}", placeholder); - if (!ImGui.BeginCombo(id, preview)) { - return; - } - - if (ImGui.Selectable("")) { - x = -1; - } - - for (var i = 0; i < items.Count; i++) { - var template = items[i].Replace("{0}", placeholder); - if (ImGui.Selectable(template, i == x)) { - x = i; - } - } - - ImGui.EndCombo(); - } - - void DrawWordPicker(string id, IReadOnlyList words, ref (int, int) x) { - var preview = x == (-1, -1) ? "" : words[x.Item1].Words[x.Item2]; - if (!ImGui.BeginCombo(id, preview)) { - return; - } - - for (var listIdx = 0; listIdx < words.Count; listIdx++) { - var list = words[listIdx]; - if (!ImGui.BeginMenu(list.Name)) { - continue; - } - - for (var wordIdx = 0; wordIdx < list.Words.Length; wordIdx++) { - if (ImGui.MenuItem(list.Words[wordIdx])) { - x = (listIdx, wordIdx); - } - } - - ImGui.EndMenu(); - } - - ImGui.EndCombo(); - } - - var pack = Pack.All.Value[this._pack]; - - var actualText = string.Empty; - if (this._part1 == -1) { - ImGui.TextUnformatted(placeholder); - } else { - var preview = new StringBuilder(); - - var template1 = pack.Templates[this._part1]; - var word1 = this._word1 == (-1, -1) ? placeholder : pack.Words[this._word1.Item1].Words[this._word1.Item2]; - preview.Append(string.Format(template1, word1)); - - if (this._conj != -1) { - var conj = pack.Conjunctions[this._conj]; - if (conj.Length != 1 || !char.IsPunctuation(conj[0])) { - preview.Append('\n'); - } - - preview.Append(conj); - preview.Append(' '); - - if (this._part2 != -1) { - var template2 = pack.Templates[this._part2]; - var word2 = this._word2 == (-1, -1) ? placeholder : pack.Words[this._word2.Item1].Words[this._word2.Item2]; - preview.Append(string.Format(template2, word2)); - } - } - - actualText = preview.ToString(); - ImGui.TextUnformatted(actualText); - } - - ImGui.Separator(); - - DrawPicker("Template##part-1", pack.Templates, ref this._part1); - if (this._part1 > -1 && pack.Templates[this._part1].Contains("{0}")) { - DrawWordPicker("Word##word-1", pack.Words, ref this._word1); - } - - DrawPicker("Conjunction##conj", pack.Conjunctions, ref this._conj); - - if (this._conj != -1) { - DrawPicker("Template##part-2", pack.Templates, ref this._part2); - if (this._part2 > -1 && pack.Templates[this._part2].Contains("{0}")) { - DrawWordPicker("Word##word-2", pack.Words, ref this._word2); - } - } - - this.ClearIfNecessary(); - - var valid = this.ValidSetup(); - if (!valid) { - ImGui.BeginDisabled(); - } - - if (ImGui.Button("Write") && valid && this.Plugin.ClientState.LocalPlayer is { } player) { - var req = new MessageRequest { - Territory = this.Plugin.ClientState.TerritoryType, - X = player.Position.X, - Y = player.Position.Y, - Z = player.Position.Z, - PackId = pack.Id, - Template1 = this._part1, - Word1List = this._word1.Item1 == -1 ? null : this._word1.Item1, - Word1Word = this._word1.Item2 == -1 ? null : this._word1.Item2, - Conjunction = this._conj == -1 ? null : this._conj, - Template2 = this._part2 == -1 ? null : this._part2, - Word2List = this._word2.Item1 == -1 ? null : this._word2.Item1, - Word2Word = this._word2.Item2 == -1 ? null : this._word2.Item2, - }; - - var json = JsonConvert.SerializeObject(req); - Task.Run(async () => { - var content = new StringContent(json) { - Headers = { - ContentType = new MediaTypeHeaderValue("application/json"), - }, - }; - - content.Headers.Add("X-Api-Key", this.Plugin.Config.ApiKey); - - var resp = await new HttpClient().PostAsync("https://tryfingerbuthole.anna.lgbt/messages", content); - var id = await resp.Content.ReadAsStringAsync(); - if (resp.IsSuccessStatusCode) { - var newMsg = new Message { - Id = Guid.Parse(id), - X = player.Position.X, - Y = player.Position.Y, - Z = player.Position.Z, - Text = actualText, - NegativeVotes = 0, - PositiveVotes = 0, - }; - - this.Plugin.Messages.Add(newMsg); - this.ResetWriter(); - this.WriterVisible = false; - } - }); - } - - if (!valid) { - ImGui.EndDisabled(); - } - - if (this.Plugin.ClientState.LocalPlayer is { } player2) { - foreach (var msg in this.Plugin.Messages.Nearby()) { - ImGui.TextUnformatted($"{msg.Text}: {Vector3.Distance(msg.Position, player2.Position):N2}"); - } - } - - ImGui.End(); - } - - private void ResetWriter() { - this._part1 = this._part2 = this._conj = -1; - this._word1 = (-1, -1); - this._word2 = (-1, -1); - } - - private void ClearIfNecessary() { - if (this._pack == -1) { - this._part1 = -1; - } - - var pack = Pack.All.Value[this._pack]; - - if (this._part1 == -1 || !pack.Templates[this._part1].Contains("{0}")) { - this._word1 = (-1, -1); - } - - if (this._conj == -1) { - this._part2 = -1; - } - - if (this._part2 == -1 || !pack.Templates[this._part2].Contains("{0}")) { - this._word2 = (-1, -1); - } - } - - private bool ValidSetup() { - if (this._pack == -1 || this._part1 == -1) { - return false; - } - - var pack = Pack.All.Value[this._pack]; - var template1 = pack.Templates[this._part1]; - var temp1Variable = template1.Contains("{0}"); - - switch (temp1Variable) { - case true when this._word1 == (-1, -1): - case false when this._word1 != (-1, -1): - return false; - } - - if (this._conj == -1 && (this._part2 != -1 || this._word2 != (-1, -1))) { - return false; - } - - if (this._conj != -1) { - if (this._part2 == -1) { - return false; - } - - var template2 = pack.Templates[this._part2]; - var temp2Variable = template2.Contains("{0}"); - - switch (temp2Variable) { - case true when this._word2 == (-1, -1): - case false when this._word2 != (-1, -1): - return false; - } - } - - return true; - } - - private void DrawViewerButton() { - if (this.ViewerVisible) { - return; - } - - var nearby = this.Plugin.Messages.Nearby().ToList(); - if (nearby.Count == 0) { - return; - } - - ImGui.SetNextWindowBgAlpha(0.5f); - if (!ImGui.Begin("##ogt-viewer-button", ImGuiWindowFlags.NoTitleBar)) { - ImGui.End(); - return; - } - - var label = "View message"; - if (nearby.Count > 1) { - label += "s"; - } - - if (ImGui.Button(label)) { - this.ViewerVisible = true; - } - - ImGui.End(); - } - - private int _viewerIdx; - - private void DrawViewer() { - if (!this.ViewerVisible) { - return; - } - - if (!ImGui.Begin("Messages", ref this.ViewerVisible)) { - ImGui.End(); - return; - } - - if (ImGui.IsWindowAppearing()) { - this._viewerIdx = 0; - } - - var nearby = this.Plugin.Messages.Nearby() - .OrderBy(msg => msg.Id) - .ToList(); - if (nearby.Count == 0) { - ImGui.TextUnformatted("No nearby messages"); - goto End; - } - - if (!ImGui.BeginTable("##viewer-table", 3)) { - goto End; - } - - ImGui.TableSetupColumn("##prev-arrow", ImGuiTableColumnFlags.WidthFixed); - ImGui.TableSetupColumn("##content", ImGuiTableColumnFlags.WidthStretch); - ImGui.TableSetupColumn("##next-arrow", ImGuiTableColumnFlags.WidthFixed); - ImGui.TableNextRow(); - - if (ImGui.TableSetColumnIndex(0)) { - var height = ImGui.GetContentRegionAvail().Y; - var buttonHeight = ImGuiHelpers.GetButtonSize("<").Y; - ImGui.Dummy(new Vector2(1, height / 2 - buttonHeight / 2 - ImGui.GetStyle().ItemSpacing.Y)); - if (this._viewerIdx == 0) { - ImGui.BeginDisabled(); - } - - if (ImGui.Button("<")) { - this._viewerIdx -= 1; - } - - if (this._viewerIdx == 0) { - ImGui.EndDisabled(); - } - } - - if (ImGui.TableSetColumnIndex(1) && this._viewerIdx > -1 && this._viewerIdx < nearby.Count) { - var message = nearby[this._viewerIdx]; - var size = ImGui.CalcTextSize(message.Text, ImGui.GetContentRegionAvail().X); - var height = ImGui.GetContentRegionAvail().Y; - ImGui.Dummy(new Vector2(1, height / 2 - size.Y / 2 - ImGui.GetStyle().ItemSpacing.Y)); - - ImGui.PushTextWrapPos(); - ImGui.TextUnformatted(message.Text); - ImGui.PopTextWrapPos(); - } - - if (ImGui.TableSetColumnIndex(2)) { - var height = ImGui.GetContentRegionAvail().Y; - var buttonHeight = ImGuiHelpers.GetButtonSize(">").Y; - ImGui.Dummy(new Vector2(1, height / 2 - buttonHeight / 2 - ImGui.GetStyle().ItemSpacing.Y)); - - if (this._viewerIdx == nearby.Count - 1) { - ImGui.BeginDisabled(); - } - - if (ImGui.Button(">")) { - this._viewerIdx += 1; - } - - if (this._viewerIdx == nearby.Count - 1) { - ImGui.EndDisabled(); - } - } - - ImGui.EndTable(); - - End: - ImGui.End(); + this.MainWindow.Draw(); + this.ViewerButton.Draw(); + this.Viewer.Draw(); } } diff --git a/client/Ui/MainWindow.cs b/client/Ui/MainWindow.cs new file mode 100644 index 0000000..264bad9 --- /dev/null +++ b/client/Ui/MainWindow.cs @@ -0,0 +1,46 @@ +using ImGuiNET; +using OrangeGuidanceTomestone.Ui.MainWindowTabs; + +namespace OrangeGuidanceTomestone.Ui; + +internal class MainWindow { + private Plugin Plugin { get; } + private List Tabs { get; } + + internal bool Visible; + + internal MainWindow(Plugin plugin) { + this.Plugin = plugin; + this.Tabs = new List { + new Write(this.Plugin), + new MessageList(this.Plugin), + }; + } + + internal void Draw() { + if (!this.Visible) { + return; + } + + if (!ImGui.Begin(this.Plugin.Name, ref this.Visible)) { + ImGui.End(); + return; + } + + if (ImGui.BeginTabBar("##ogt-main-tabs")) { + foreach (var tab in this.Tabs) { + if (!ImGui.BeginTabItem(tab.Name)) { + continue; + } + + tab.Draw(); + + ImGui.EndTabItem(); + } + + ImGui.EndTabBar(); + } + + ImGui.End(); + } +} diff --git a/client/Ui/MainWindowTabs/ITab.cs b/client/Ui/MainWindowTabs/ITab.cs new file mode 100644 index 0000000..2c5ceda --- /dev/null +++ b/client/Ui/MainWindowTabs/ITab.cs @@ -0,0 +1,6 @@ +namespace OrangeGuidanceTomestone.Ui.MainWindowTabs; + +public interface ITab { + public string Name { get; } + public void Draw(); +} diff --git a/client/Ui/MainWindowTabs/MessageList.cs b/client/Ui/MainWindowTabs/MessageList.cs new file mode 100644 index 0000000..cea6bb1 --- /dev/null +++ b/client/Ui/MainWindowTabs/MessageList.cs @@ -0,0 +1,53 @@ +using ImGuiNET; +using Newtonsoft.Json; +using OrangeGuidanceTomestone.Helpers; + +namespace OrangeGuidanceTomestone.Ui.MainWindowTabs; + +internal class MessageList : ITab { + public string Name => "Your messages"; + private Plugin Plugin { get; } + + private SemaphoreSlim MessagesMutex { get; } = new(1, 1); + private List Messages { get; } = new(); + + internal MessageList(Plugin plugin) { + this.Plugin = plugin; + } + + public void Draw() { + if (ImGui.Button("Refresh")) { + this.Refresh(); + } + + this.MessagesMutex.Wait(); + + foreach (var message in this.Messages) { + ImGui.TextUnformatted(message.Text); + } + + this.MessagesMutex.Release(); + } + + private void Refresh() { + Task.Run(async () => { + var resp = await ServerHelper.SendRequest( + this.Plugin.Config.ApiKey, + HttpMethod.Get, + "/messages" + ); + var json = await resp.Content.ReadAsStringAsync(); + var messages = JsonConvert.DeserializeObject(json)!; + await this.MessagesMutex.WaitAsync(); + this.Messages.Clear(); + this.Messages.AddRange(messages); + this.MessagesMutex.Release(); + }); + } + + internal void Add(MessageWithTerritory message) { + this.Messages.Clear(); + this.Messages.Add(message); + this.MessagesMutex.Release(); + } +} diff --git a/client/Ui/MainWindowTabs/Write.cs b/client/Ui/MainWindowTabs/Write.cs new file mode 100644 index 0000000..cd6ad7c --- /dev/null +++ b/client/Ui/MainWindowTabs/Write.cs @@ -0,0 +1,252 @@ +using System.Text; +using ImGuiNET; +using Newtonsoft.Json; +using OrangeGuidanceTomestone.Helpers; + +namespace OrangeGuidanceTomestone.Ui.MainWindowTabs; + +internal class Write : ITab { + public string Name => "Write"; + + private Plugin Plugin { get; } + + private int _pack; + private int _part1 = -1; + private (int, int) _word1 = (-1, -1); + private int _conj = -1; + private int _part2 = -1; + private (int, int) _word2 = (-1, -1); + + internal Write(Plugin plugin) { + this.Plugin = plugin; + } + + public void Draw() { + var packPrev = Pack.All.Value[this._pack].Name; + if (ImGui.BeginCombo("Pack", packPrev)) { + for (var i = 0; i < Pack.All.Value.Length; i++) { + var selPack = Pack.All.Value[i]; + if (!ImGui.Selectable(selPack.Name)) { + continue; + } + + this._pack = i; + this.ResetWriter(); + } + + ImGui.EndCombo(); + } + + const string placeholder = "****"; + + void DrawPicker(string id, IReadOnlyList items, ref int x) { + var preview = x == -1 ? "" : items[x].Replace("{0}", placeholder); + if (!ImGui.BeginCombo(id, preview)) { + return; + } + + if (ImGui.Selectable("")) { + x = -1; + } + + for (var i = 0; i < items.Count; i++) { + var template = items[i].Replace("{0}", placeholder); + if (ImGui.Selectable(template, i == x)) { + x = i; + } + } + + ImGui.EndCombo(); + } + + void DrawWordPicker(string id, IReadOnlyList words, ref (int, int) x) { + var preview = x == (-1, -1) ? "" : words[x.Item1].Words[x.Item2]; + if (!ImGui.BeginCombo(id, preview)) { + return; + } + + for (var listIdx = 0; listIdx < words.Count; listIdx++) { + var list = words[listIdx]; + if (!ImGui.BeginMenu(list.Name)) { + continue; + } + + for (var wordIdx = 0; wordIdx < list.Words.Length; wordIdx++) { + if (ImGui.MenuItem(list.Words[wordIdx])) { + x = (listIdx, wordIdx); + } + } + + ImGui.EndMenu(); + } + + ImGui.EndCombo(); + } + + var pack = Pack.All.Value[this._pack]; + + var actualText = string.Empty; + if (this._part1 == -1) { + ImGui.TextUnformatted(placeholder); + } else { + var preview = new StringBuilder(); + + var template1 = pack.Templates[this._part1]; + var word1 = this._word1 == (-1, -1) ? placeholder : pack.Words[this._word1.Item1].Words[this._word1.Item2]; + preview.Append(string.Format(template1, word1)); + + if (this._conj != -1) { + var conj = pack.Conjunctions[this._conj]; + if (conj.Length != 1 || !char.IsPunctuation(conj[0])) { + preview.Append('\n'); + } + + preview.Append(conj); + preview.Append(' '); + + if (this._part2 != -1) { + var template2 = pack.Templates[this._part2]; + var word2 = this._word2 == (-1, -1) ? placeholder : pack.Words[this._word2.Item1].Words[this._word2.Item2]; + preview.Append(string.Format(template2, word2)); + } + } + + actualText = preview.ToString(); + ImGui.TextUnformatted(actualText); + } + + ImGui.Separator(); + + DrawPicker("Template##part-1", pack.Templates, ref this._part1); + if (this._part1 > -1 && pack.Templates[this._part1].Contains("{0}")) { + DrawWordPicker("Word##word-1", pack.Words, ref this._word1); + } + + DrawPicker("Conjunction##conj", pack.Conjunctions, ref this._conj); + + if (this._conj != -1) { + DrawPicker("Template##part-2", pack.Templates, ref this._part2); + if (this._part2 > -1 && pack.Templates[this._part2].Contains("{0}")) { + DrawWordPicker("Word##word-2", pack.Words, ref this._word2); + } + } + + this.ClearIfNecessary(); + + var valid = this.ValidSetup(); + if (!valid) { + ImGui.BeginDisabled(); + } + + if (ImGui.Button("Write") && valid && this.Plugin.ClientState.LocalPlayer is { } player) { + var req = new MessageRequest { + Territory = this.Plugin.ClientState.TerritoryType, + X = player.Position.X, + Y = player.Position.Y, + Z = player.Position.Z, + PackId = pack.Id, + Template1 = this._part1, + Word1List = this._word1.Item1 == -1 ? null : this._word1.Item1, + Word1Word = this._word1.Item2 == -1 ? null : this._word1.Item2, + Conjunction = this._conj == -1 ? null : this._conj, + Template2 = this._part2 == -1 ? null : this._part2, + Word2List = this._word2.Item1 == -1 ? null : this._word2.Item1, + Word2Word = this._word2.Item2 == -1 ? null : this._word2.Item2, + }; + + var json = JsonConvert.SerializeObject(req); + Task.Run(async () => { + var resp = await ServerHelper.SendRequest( + this.Plugin.Config.ApiKey, + HttpMethod.Post, + "/messages", + "application/json", + new StringContent(json) + ); + var id = await resp.Content.ReadAsStringAsync(); + if (resp.IsSuccessStatusCode) { + var newMsg = new Message { + Id = Guid.Parse(id), + X = player.Position.X, + Y = player.Position.Y, + Z = player.Position.Z, + Text = actualText, + NegativeVotes = 0, + PositiveVotes = 0, + }; + + this.Plugin.Messages.Add(newMsg); + this.ResetWriter(); + this.Plugin.Ui.MainWindow.Visible = false; + } + }); + } + + if (!valid) { + ImGui.EndDisabled(); + } + } + + private void ResetWriter() { + this._part1 = this._part2 = this._conj = -1; + this._word1 = (-1, -1); + this._word2 = (-1, -1); + } + + private void ClearIfNecessary() { + if (this._pack == -1) { + this._part1 = -1; + } + + var pack = Pack.All.Value[this._pack]; + + if (this._part1 == -1 || !pack.Templates[this._part1].Contains("{0}")) { + this._word1 = (-1, -1); + } + + if (this._conj == -1) { + this._part2 = -1; + } + + if (this._part2 == -1 || !pack.Templates[this._part2].Contains("{0}")) { + this._word2 = (-1, -1); + } + } + + private bool ValidSetup() { + if (this._pack == -1 || this._part1 == -1) { + return false; + } + + var pack = Pack.All.Value[this._pack]; + var template1 = pack.Templates[this._part1]; + var temp1Variable = template1.Contains("{0}"); + + switch (temp1Variable) { + case true when this._word1 == (-1, -1): + case false when this._word1 != (-1, -1): + return false; + } + + if (this._conj == -1 && (this._part2 != -1 || this._word2 != (-1, -1))) { + return false; + } + + if (this._conj != -1) { + if (this._part2 == -1) { + return false; + } + + var template2 = pack.Templates[this._part2]; + var temp2Variable = template2.Contains("{0}"); + + switch (temp2Variable) { + case true when this._word2 == (-1, -1): + case false when this._word2 != (-1, -1): + return false; + } + } + + return true; + } +} diff --git a/client/Ui/Viewer.cs b/client/Ui/Viewer.cs new file mode 100644 index 0000000..1880ce2 --- /dev/null +++ b/client/Ui/Viewer.cs @@ -0,0 +1,100 @@ +using System.Numerics; +using Dalamud.Interface; +using ImGuiNET; + +namespace OrangeGuidanceTomestone.Ui; + +internal class Viewer { + private Plugin Plugin { get; } + + internal bool Visible; + + private int _idx; + + internal Viewer(Plugin plugin) { + this.Plugin = plugin; + } + + internal void Draw() { + if (!this.Visible) { + return; + } + + if (!ImGui.Begin("Messages", ref this.Visible)) { + ImGui.End(); + return; + } + + if (ImGui.IsWindowAppearing()) { + this._idx = 0; + } + + var nearby = this.Plugin.Messages.Nearby() + .OrderBy(msg => msg.Id) + .ToList(); + if (nearby.Count == 0) { + ImGui.TextUnformatted("No nearby messages"); + goto End; + } + + if (!ImGui.BeginTable("##viewer-table", 3)) { + goto End; + } + + ImGui.TableSetupColumn("##prev-arrow", ImGuiTableColumnFlags.WidthFixed); + ImGui.TableSetupColumn("##content", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("##next-arrow", ImGuiTableColumnFlags.WidthFixed); + ImGui.TableNextRow(); + + if (ImGui.TableSetColumnIndex(0)) { + var height = ImGui.GetContentRegionAvail().Y; + var buttonHeight = ImGuiHelpers.GetButtonSize("<").Y; + ImGui.Dummy(new Vector2(1, height / 2 - buttonHeight / 2 - ImGui.GetStyle().ItemSpacing.Y)); + if (this._idx == 0) { + ImGui.BeginDisabled(); + } + + if (ImGui.Button("<")) { + this._idx -= 1; + } + + if (this._idx == 0) { + ImGui.EndDisabled(); + } + } + + if (ImGui.TableSetColumnIndex(1) && this._idx > -1 && this._idx < nearby.Count) { + var message = nearby[this._idx]; + var size = ImGui.CalcTextSize(message.Text, ImGui.GetContentRegionAvail().X); + var height = ImGui.GetContentRegionAvail().Y; + ImGui.Dummy(new Vector2(1, height / 2 - size.Y / 2 - ImGui.GetStyle().ItemSpacing.Y)); + + ImGui.PushTextWrapPos(); + ImGui.TextUnformatted(message.Text); + ImGui.PopTextWrapPos(); + } + + if (ImGui.TableSetColumnIndex(2)) { + var height = ImGui.GetContentRegionAvail().Y; + var buttonHeight = ImGuiHelpers.GetButtonSize(">").Y; + ImGui.Dummy(new Vector2(1, height / 2 - buttonHeight / 2 - ImGui.GetStyle().ItemSpacing.Y)); + + if (this._idx == nearby.Count - 1) { + ImGui.BeginDisabled(); + } + + if (ImGui.Button(">")) { + this._idx += 1; + } + + if (this._idx == nearby.Count - 1) { + ImGui.EndDisabled(); + } + } + + ImGui.EndTable(); + + End: + ImGui.End(); + } +} diff --git a/client/Ui/ViewerButton.cs b/client/Ui/ViewerButton.cs new file mode 100644 index 0000000..23fa230 --- /dev/null +++ b/client/Ui/ViewerButton.cs @@ -0,0 +1,39 @@ +using ImGuiNET; + +namespace OrangeGuidanceTomestone.Ui; + +internal class ViewerButton { + private Plugin Plugin { get; } + + internal ViewerButton(Plugin plugin) { + this.Plugin = plugin; + } + + internal void Draw() { + if (this.Plugin.Ui.Viewer.Visible) { + return; + } + + var nearby = this.Plugin.Messages.Nearby().ToList(); + if (nearby.Count == 0) { + return; + } + + ImGui.SetNextWindowBgAlpha(0.5f); + if (!ImGui.Begin("##ogt-viewer-button", ImGuiWindowFlags.NoTitleBar)) { + ImGui.End(); + return; + } + + var label = "View message"; + if (nearby.Count > 1) { + label += "s"; + } + + if (ImGui.Button(label)) { + this.Plugin.Ui.Viewer.Visible = true; + } + + ImGui.End(); + } +} diff --git a/server/src/message.rs b/server/src/message.rs index 6c3b92c..0020b66 100644 --- a/server/src/message.rs +++ b/server/src/message.rs @@ -43,7 +43,7 @@ pub struct RetrievedMessage { #[derive(Debug, Serialize)] pub struct RetrievedMessageTerritory { pub id: String, - puv territory: i64, + pub territory: i64, pub x: f64, pub y: f64, pub z: f64, diff --git a/server/src/pack.rs b/server/src/pack.rs index 08db311..236fa94 100644 --- a/server/src/pack.rs +++ b/server/src/pack.rs @@ -35,7 +35,7 @@ impl Pack { if let Some(template_2_idx) = template_2_idx { let conj = self.conjunctions.get(conj_idx)?; let is_punc = conj.len() == 1 && conj.chars().next().map(|x| x.is_ascii_punctuation()).unwrap_or(false); - if is_punch { + if is_punc { formatted.push_str(conj); formatted.push('\n'); } else { diff --git a/server/src/web.rs b/server/src/web.rs index 03aca29..da4108b 100644 --- a/server/src/web.rs +++ b/server/src/web.rs @@ -77,6 +77,7 @@ async fn handle_rejection(err: Rejection) -> Result { WebError::InvalidAuthToken => StatusCode::BAD_REQUEST, WebError::InvalidPackId => StatusCode::NOT_FOUND, WebError::InvalidIndex => StatusCode::NOT_FOUND, + WebError::TooManyMessages => StatusCode::BAD_REQUEST, } } else { eprintln!("{:#?}", err); diff --git a/server/src/web/write.rs b/server/src/web/write.rs index 5527374..132f703 100644 --- a/server/src/web/write.rs +++ b/server/src/web/write.rs @@ -28,7 +28,7 @@ async fn logic(state: Arc, id: i64, message: Message) -> Result