diff --git a/client/Configuration.cs b/client/Configuration.cs index c5789f7..c8bbeb2 100644 --- a/client/Configuration.cs +++ b/client/Configuration.cs @@ -20,6 +20,10 @@ public class Configuration : IPluginConfiguration { public bool HideTitlebar; public bool ShowEmotes = true; public float EmoteAlpha = 25.0f; + public float SignAlpha = 100.0f; + public float SignRed = 100.0f; + public float SignGreen = 100.0f; + public float SignBlue = 100.0f; public float ViewerOpacity = 100.0f; public int DefaultGlyph = 3; } diff --git a/client/Ui/MainWindowTabs/Settings.cs b/client/Ui/MainWindowTabs/Settings.cs index 3cfbd7c..bdd1b91 100644 --- a/client/Ui/MainWindowTabs/Settings.cs +++ b/client/Ui/MainWindowTabs/Settings.cs @@ -1,6 +1,7 @@ using System.Globalization; using System.Numerics; using Dalamud.Utility; +using FFXIVClientStructs.Interop; using ImGuiNET; using Lumina.Excel.GeneratedSheets; using OrangeGuidanceTomestone.Helpers; @@ -38,6 +39,7 @@ internal class Settings : ITab { ("General", this.DrawGeneral), ("Writer", this.DrawWriter), ("Viewer", this.DrawViewer), + ("Signs", this.DrawSigns), ("Unlocks", this.DrawUnlocks), ("Account", this.DrawAccount), ("Debug", this.DrawDebug), @@ -121,7 +123,6 @@ internal class Settings : ITab { anyChanged |= vfx |= ImGui.Checkbox("Disable in Deep Dungeons", ref this.Plugin.Config.DisableDeepDungeon); anyChanged |= vfx |= ImGui.Checkbox("Disable in cutscenes", ref this.Plugin.Config.DisableInCutscene); anyChanged |= vfx |= ImGui.Checkbox("Disable in /gpose", ref this.Plugin.Config.DisableInGpose); - anyChanged |= vfx |= ImGui.Checkbox("Remove glow effect from signs", ref this.Plugin.Config.RemoveGlow); var tt = this.Plugin.DataManager.GetExcelSheet(); if (tt == null) { @@ -226,6 +227,81 @@ internal class Settings : ITab { anyChanged |= ImGui.SliderFloat("Player emote opacity", ref this.Plugin.Config.EmoteAlpha, 0f, 100f, "%.2f%%"); } + private void DrawSigns(ref bool anyChanged, ref bool vfx) { + anyChanged |= vfx |= ImGui.Checkbox("Remove glow effect from signs", ref this.Plugin.Config.RemoveGlow); + if (ImGui.SliderFloat("Sign opacity", ref this.Plugin.Config.SignAlpha, 0, 100, "%.2f%%")) { + anyChanged = true; + + this.WithEachVfx(vfx => { + unsafe { + vfx.Value->Alpha = Math.Clamp(this.Plugin.Config.SignAlpha / 100.0f, 0, 1); + } + }); + } + + var intensity = (this.Plugin.Config.SignRed + this.Plugin.Config.SignGreen + this.Plugin.Config.SignBlue) / 3; + if (ImGui.SliderFloat("Sign intensity", ref intensity, 0, 100, "%.2f%%")) { + anyChanged = true; + this.Plugin.Config.SignRed = intensity; + this.Plugin.Config.SignGreen = intensity; + this.Plugin.Config.SignBlue = intensity; + + var scaled = Math.Clamp(intensity / 100.0f, 0, 1); + this.WithEachVfx(vfx => { + unsafe { + vfx.Value->Red = scaled; + vfx.Value->Green = scaled; + vfx.Value->Blue = scaled; + } + }); + } + + if (ImGui.TreeNodeEx("Individual colour intensities")) { + using var treePop = new OnDispose(ImGui.TreePop); + + if (ImGui.SliderFloat("Red intensity", ref this.Plugin.Config.SignRed, 0, 100, "%.2f%%")) { + anyChanged = true; + this.WithEachVfx(vfx => { + unsafe { + vfx.Value->Red = Math.Clamp(this.Plugin.Config.SignRed / 100, 0, 100); + } + }); + } + + if (ImGui.SliderFloat("Green intensity", ref this.Plugin.Config.SignGreen, 0, 100, "%.2f%%")) { + anyChanged = true; + this.WithEachVfx(vfx => { + unsafe { + vfx.Value->Green = Math.Clamp(this.Plugin.Config.SignGreen / 100, 0, 100); + } + }); + } + + if (ImGui.SliderFloat("Blue intensity", ref this.Plugin.Config.SignBlue, 0, 100, "%.2f%%")) { + anyChanged = true; + this.WithEachVfx(vfx => { + unsafe { + vfx.Value->Blue = Math.Clamp(this.Plugin.Config.SignBlue / 100, 0, 100); + } + }); + } + } + } + + private void WithEachVfx(Action> action) { + if (!this.Plugin.Vfx.Mutex.With(TimeSpan.Zero, out var releaser)) { + return; + } + + using (releaser) { + foreach (var (_, ptr) in this.Plugin.Vfx.Spawned) { + unsafe { + action((Vfx.VfxStruct*) ptr); + } + } + } + } + private void DrawUnlocks(ref bool anyChanged, ref bool vfx) { this.ExtraCodeInput(); } diff --git a/client/Util/SemaphoreExt.cs b/client/Util/SemaphoreExt.cs index 87c7b24..3c7ef3f 100644 --- a/client/Util/SemaphoreExt.cs +++ b/client/Util/SemaphoreExt.cs @@ -6,6 +6,16 @@ internal static class SemaphoreExt { return new OnDispose(() => semaphore.Release()); } + internal static bool With(this SemaphoreSlim semaphore, TimeSpan timeout, out OnDispose? releaser) { + if (semaphore.Wait(timeout)) { + releaser = new OnDispose(() => semaphore.Release()); + return true; + } + + releaser = null; + return false; + } + internal static async Task WithAsync(this SemaphoreSlim semaphore, CancellationToken token = default) { await semaphore.WaitAsync(token); return new OnDispose(() => semaphore.Release()); diff --git a/client/Vfx.cs b/client/Vfx.cs index 355b63a..f01a71b 100644 --- a/client/Vfx.cs +++ b/client/Vfx.cs @@ -133,6 +133,12 @@ internal unsafe class Vfx : IDisposable { // update rotation vfx->Rotation = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); + // set alpha and colours from config + vfx->Red = Math.Clamp(this.Plugin.Config.SignRed / 100, 0, 100); + vfx->Green = Math.Clamp(this.Plugin.Config.SignGreen / 100, 0, 100); + vfx->Blue = Math.Clamp(this.Plugin.Config.SignBlue / 100, 0, 100); + vfx->Alpha = Math.Clamp(this.Plugin.Config.SignAlpha / 100, 0, 100); + // remove flag that sometimes causes vfx to not appear? vfx->SomeFlags &= 0xF7; @@ -176,6 +182,18 @@ internal unsafe class Vfx : IDisposable { [FieldOffset(0x248)] public byte SomeFlags; + + [FieldOffset(0x260)] + public float Red; + + [FieldOffset(0x264)] + public float Green; + + [FieldOffset(0x268)] + public float Blue; + + [FieldOffset(0x26C)] + public float Alpha; } }