From 8daf355f8f97f61cb03a5a10f8aecfcb63a486d2 Mon Sep 17 00:00:00 2001 From: Jackson <9527380+Jaksuhn@users.noreply.github.com> Date: Fri, 22 Mar 2024 20:20:38 +0000 Subject: [PATCH 1/6] add auto recording --- BossMod/Framework/Plugin.cs | 16 +++++++ BossMod/Framework/Service.cs | 1 + BossMod/Replay/ReplayManagementConfig.cs | 6 +++ BossMod/Replay/ReplayManagementWindow.cs | 54 +++++++++++++++++++++++- 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/BossMod/Framework/Plugin.cs b/BossMod/Framework/Plugin.cs index cea188529..d6ecec1e3 100644 --- a/BossMod/Framework/Plugin.cs +++ b/BossMod/Framework/Plugin.cs @@ -46,6 +46,8 @@ public Plugin( Service.WindowSystem = new("vbm"); //Service.Device = pluginInterface.UiBuilder.Device; Service.Condition.ConditionChange += OnConditionChanged; + Service.DutyState.DutyStarted += OnDutyStarted; + Service.DutyState.DutyCompleted += OnDutyCompleted; MultiboxUnlock.Exec(); Network.IDScramble.Initialize(); Camera.Instance = new(); @@ -82,6 +84,8 @@ public Plugin( public void Dispose() { Service.Condition.ConditionChange -= OnConditionChanged; + Service.DutyState.DutyStarted -= OnDutyStarted; + Service.DutyState.DutyCompleted -= OnDutyCompleted; _wndDebug.Dispose(); _wndReplay.Dispose(); _wndBossmodHints.Dispose(); @@ -160,5 +164,17 @@ private void OnConditionChanged(ConditionFlag flag, bool value) { Service.Log($"Condition chage: {flag}={value}"); } + + private void OnDutyStarted(object? sender, ushort e) + { + if (!Service.Config.Get().AutoRecord) return; + _wndReplay.StartRecording(); + } + + private void OnDutyCompleted(object? sender, ushort e) + { + if (!Service.Config.Get().AutoStop) return; + _wndReplay.StopRecording(); + } } } diff --git a/BossMod/Framework/Service.cs b/BossMod/Framework/Service.cs index 0bb4ee55d..487042063 100644 --- a/BossMod/Framework/Service.cs +++ b/BossMod/Framework/Service.cs @@ -27,6 +27,7 @@ public class Service [PluginService] public static IFramework Framework { get; private set; } [PluginService] public static ITextureProvider Texture { get; private set; } [PluginService] public static ICommandManager CommandManager { get; private set; } + [PluginService] public static IDutyState DutyState { get; private set; } [PluginService] public static DalamudPluginInterface PluginInterface { get; private set; } #pragma warning restore CS8618 diff --git a/BossMod/Replay/ReplayManagementConfig.cs b/BossMod/Replay/ReplayManagementConfig.cs index 5183a99d6..26578102c 100644 --- a/BossMod/Replay/ReplayManagementConfig.cs +++ b/BossMod/Replay/ReplayManagementConfig.cs @@ -6,6 +6,12 @@ public class ReplayManagementConfig : ConfigNode [PropertyDisplay("Show replay management UI")] public bool ShowUI = false; + [PropertyDisplay("Auto record replays on duty start")] + public bool AutoRecord = false; + + [PropertyDisplay("Auto stop replays on duty end")] + public bool AutoStop = false; + [PropertyDisplay("Store server packets in the replay")] public bool DumpServerPackets = false; diff --git a/BossMod/Replay/ReplayManagementWindow.cs b/BossMod/Replay/ReplayManagementWindow.cs index 2c96bd5cf..f467f9e08 100644 --- a/BossMod/Replay/ReplayManagementWindow.cs +++ b/BossMod/Replay/ReplayManagementWindow.cs @@ -1,6 +1,9 @@ -using ImGuiNET; +using FFXIVClientStructs.FFXIV.Client.Game.UI; +using ImGuiNET; +using Lumina.Excel.GeneratedSheets; using System; using System.IO; +using System.Linq; namespace BossMod { @@ -56,7 +59,7 @@ public override void Draw() { try { - _recorder = new(_ws, _config.WorldLogFormat, true, _logDir, "World"); + _recorder = new(_ws, _config.WorldLogFormat, true, _logDir, $"{GetPrefix()}"); } catch (Exception ex) { @@ -86,6 +89,30 @@ public override void Draw() _manager.Draw(); } + public void StartRecording() + { + if (_recorder == null) + { + try + { + _recorder = new(_ws, _config.WorldLogFormat, true, _logDir, $"{GetPrefix()}"); + } + catch (Exception ex) + { + Service.Log($"Failed to start recording: {ex}"); + } + } + } + + public void StopRecording() + { + if (_recorder != null) + { + _recorder.Dispose(); + _recorder = null; + } + } + public override void OnClose() { SetVisible(false); @@ -93,5 +120,28 @@ public override void OnClose() private void ApplyConfig(object? sender, EventArgs args) => IsOpen = _config.ShowUI; private void UpdateTitle() => WindowName = $"Replay recording: {(_recorder != null ? "in progress..." : "idle")}{_windowID}"; + private static unsafe string GetPrefix() + { + var prefix = "World"; + var row = Service.LuminaGameData!.GetExcelSheet()!.GetRow(Service.ClientState.TerritoryType); + if (row != null) + { + if (row.ContentFinderCondition.Value!.RowId != 0) + prefix = row.ContentFinderCondition.Value.Name.RawString; + else + prefix = row.PlaceName.Value?.NameNoArticle.RawString ?? prefix; + } + + var cf = ContentsFinder.Instance(); + var unrestricted = cf->IsUnrestrictedParty ? "U" : ""; + var levelsync = cf->IsLevelSync ? "LS" : ""; + var minilvl = cf->IsMinimalIL ? "MI" : ""; + var noecho = cf->IsSilenceEcho ? "NE" : ""; + var dfsettings = string.Join(", ", new[] { unrestricted, levelsync, minilvl, noecho }.Where(s => !string.IsNullOrEmpty(s))); + if (dfsettings != null) + prefix += $"_{dfsettings}"; + + return prefix; + } } } From 271f4933f9be71fb7220041c460d27a650995cdb Mon Sep 17 00:00:00 2001 From: Jackson <9527380+Jaksuhn@users.noreply.github.com> Date: Fri, 22 Mar 2024 23:26:34 +0000 Subject: [PATCH 2/6] add auto delete feature --- BossMod/Config/ConfigNode.cs | 16 +++++++++++++++ BossMod/Config/ConfigUI.cs | 26 ++++++++++++++++++++++++ BossMod/Replay/ReplayManagementConfig.cs | 4 ++++ BossMod/Replay/ReplayManagementWindow.cs | 16 +++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/BossMod/Config/ConfigNode.cs b/BossMod/Config/ConfigNode.cs index bdc1a5077..334379a52 100644 --- a/BossMod/Config/ConfigNode.cs +++ b/BossMod/Config/ConfigNode.cs @@ -60,6 +60,22 @@ public PropertySliderAttribute(float min, float max) } } + // attribute that specifies slider should be used for displaying float property + [AttributeUsage(AttributeTargets.Field)] + public class PropertyIntSliderAttribute : Attribute + { + public float Speed = 1; + public int Min; + public int Max; + public bool Logarithmic; + + public PropertyIntSliderAttribute(int min, int max) + { + Min = min; + Max = max; + } + } + // base class for configuration nodes public abstract class ConfigNode { diff --git a/BossMod/Config/ConfigUI.cs b/BossMod/Config/ConfigUI.cs index 3a64db8d0..2585e4701 100644 --- a/BossMod/Config/ConfigUI.cs +++ b/BossMod/Config/ConfigUI.cs @@ -154,6 +154,7 @@ private void DrawNodes(List nodes) bool v => DrawProperty(props, n.Node, field, v), Enum v => DrawProperty(props, n.Node, field, v), float v => DrawProperty(props, n.Node, field, v), + int v => DrawProperty(props, n.Node, field, v), GroupAssignment v => DrawProperty(props, n.Node, field, v), _ => false }; @@ -224,6 +225,31 @@ private bool DrawProperty(PropertyDisplayAttribute props, ConfigNode node, Field return true; } + private bool DrawProperty(PropertyDisplayAttribute props, ConfigNode node, FieldInfo member, int v) + { + var slider = member.GetCustomAttribute(); + if (slider != null) + { + var flags = ImGuiSliderFlags.None; + if (slider.Logarithmic) + flags |= ImGuiSliderFlags.Logarithmic; + if (ImGui.DragInt(props.Label, ref v, slider.Speed, slider.Min, slider.Max, "%d", flags)) + { + member.SetValue(node, v); + node.NotifyModified(); + } + } + else + { + if (ImGui.InputInt(props.Label, ref v)) + { + member.SetValue(node, v); + node.NotifyModified(); + } + } + return true; + } + private bool DrawProperty(PropertyDisplayAttribute props, ConfigNode node, FieldInfo member, GroupAssignment v) { var group = member.GetCustomAttribute(); diff --git a/BossMod/Replay/ReplayManagementConfig.cs b/BossMod/Replay/ReplayManagementConfig.cs index 26578102c..2b1a4fde7 100644 --- a/BossMod/Replay/ReplayManagementConfig.cs +++ b/BossMod/Replay/ReplayManagementConfig.cs @@ -12,6 +12,10 @@ public class ReplayManagementConfig : ConfigNode [PropertyDisplay("Auto stop replays on duty end")] public bool AutoStop = false; + [PropertyDisplay("Max replays to keep before removal")] + [PropertyIntSlider(0, 1000, Speed = 1f, Logarithmic = false)] + public int MaxReplays = 0; + [PropertyDisplay("Store server packets in the replay")] public bool DumpServerPackets = false; diff --git a/BossMod/Replay/ReplayManagementWindow.cs b/BossMod/Replay/ReplayManagementWindow.cs index f467f9e08..b4785f9ee 100644 --- a/BossMod/Replay/ReplayManagementWindow.cs +++ b/BossMod/Replay/ReplayManagementWindow.cs @@ -2,6 +2,7 @@ using ImGuiNET; using Lumina.Excel.GeneratedSheets; using System; +using System.Collections.Generic; using System.IO; using System.Linq; @@ -93,6 +94,21 @@ public void StartRecording() { if (_recorder == null) { + try + { + IEnumerable filesToDelete = Enumerable.Empty(); + if (_config.MaxReplays > 0) + if (_logDir.GetFiles().Length >= _config.MaxReplays) + filesToDelete = _logDir.GetFiles().OrderBy(f => f.LastWriteTime).Take(_logDir.GetFiles().Length - _config.MaxReplays); + if (filesToDelete != null) + foreach (var f in filesToDelete) + f.Delete(); + } + catch (Exception ex) + { + Service.Log($"Failed to delete old replays: {ex}"); + } + try { _recorder = new(_ws, _config.WorldLogFormat, true, _logDir, $"{GetPrefix()}"); From f240bb27fa52f844078ec85bb8e5d9d262298924 Mon Sep 17 00:00:00 2001 From: Jackson <9527380+Jaksuhn@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:11:21 +0000 Subject: [PATCH 3/6] Update ReplayManagementWindow.cs --- BossMod/Replay/ReplayManagementWindow.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/BossMod/Replay/ReplayManagementWindow.cs b/BossMod/Replay/ReplayManagementWindow.cs index b4785f9ee..fcb6e86b1 100644 --- a/BossMod/Replay/ReplayManagementWindow.cs +++ b/BossMod/Replay/ReplayManagementWindow.cs @@ -96,13 +96,11 @@ public void StartRecording() { try { - IEnumerable filesToDelete = Enumerable.Empty(); if (_config.MaxReplays > 0) - if (_logDir.GetFiles().Length >= _config.MaxReplays) - filesToDelete = _logDir.GetFiles().OrderBy(f => f.LastWriteTime).Take(_logDir.GetFiles().Length - _config.MaxReplays); - if (filesToDelete != null) - foreach (var f in filesToDelete) - f.Delete(); + { + var files = _logDir.GetFiles().OrderBy(f => f.LastWriteTime).ToList(); + files.Take(files.Count - _config.MaxReplays).ToList().ForEach(f => f.Delete()); + } } catch (Exception ex) { From 10e5ea2abd04f26ccdcca50da52289fb58ac487c Mon Sep 17 00:00:00 2001 From: Jackson <9527380+Jaksuhn@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:12:25 +0000 Subject: [PATCH 4/6] Update ReplayManagementWindow.cs --- BossMod/Replay/ReplayManagementWindow.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/BossMod/Replay/ReplayManagementWindow.cs b/BossMod/Replay/ReplayManagementWindow.cs index fcb6e86b1..d885a4b07 100644 --- a/BossMod/Replay/ReplayManagementWindow.cs +++ b/BossMod/Replay/ReplayManagementWindow.cs @@ -2,7 +2,6 @@ using ImGuiNET; using Lumina.Excel.GeneratedSheets; using System; -using System.Collections.Generic; using System.IO; using System.Linq; From ac0300b6afdbc87024f0c3eeccb58f5c8da56dca Mon Sep 17 00:00:00 2001 From: Jackson <9527380+Jaksuhn@users.noreply.github.com> Date: Tue, 26 Mar 2024 00:51:30 +0000 Subject: [PATCH 5/6] swap to checking on zone change instead of duty state --- BossMod/Framework/Plugin.cs | 18 ++++++++++++++++++ BossMod/Replay/ReplayManagementWindow.cs | 2 ++ 2 files changed, 20 insertions(+) diff --git a/BossMod/Framework/Plugin.cs b/BossMod/Framework/Plugin.cs index d6ecec1e3..e53720ce2 100644 --- a/BossMod/Framework/Plugin.cs +++ b/BossMod/Framework/Plugin.cs @@ -4,6 +4,7 @@ using Dalamud.IoC; using Dalamud.Plugin; using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.Game; using System; using System.Reflection; @@ -48,6 +49,7 @@ public Plugin( Service.Condition.ConditionChange += OnConditionChanged; Service.DutyState.DutyStarted += OnDutyStarted; Service.DutyState.DutyCompleted += OnDutyCompleted; + Service.ClientState.TerritoryChanged += OnZoneChange; MultiboxUnlock.Exec(); Network.IDScramble.Initialize(); Camera.Instance = new(); @@ -86,6 +88,7 @@ public void Dispose() Service.Condition.ConditionChange -= OnConditionChanged; Service.DutyState.DutyStarted -= OnDutyStarted; Service.DutyState.DutyCompleted -= OnDutyCompleted; + Service.ClientState.TerritoryChanged -= OnZoneChange; _wndDebug.Dispose(); _wndReplay.Dispose(); _wndBossmodHints.Dispose(); @@ -176,5 +179,20 @@ private void OnDutyCompleted(object? sender, ushort e) if (!Service.Config.Get().AutoStop) return; _wndReplay.StopRecording(); } + + private unsafe void OnZoneChange(ushort obj) + { + if (GameMain.Instance()->CurrentContentFinderConditionId != 0 && !_wndReplay.IsRecording() && Service.Config.Get().AutoRecord) + { + _wndReplay.StartRecording(); + return; + } + + if (_wndReplay.IsRecording() && Service.Config.Get().AutoStop) + { + _wndReplay.StopRecording(); + return; + } + } } } diff --git a/BossMod/Replay/ReplayManagementWindow.cs b/BossMod/Replay/ReplayManagementWindow.cs index d885a4b07..bbb755fed 100644 --- a/BossMod/Replay/ReplayManagementWindow.cs +++ b/BossMod/Replay/ReplayManagementWindow.cs @@ -126,6 +126,8 @@ public void StopRecording() } } + public bool IsRecording() => _recorder != null; + public override void OnClose() { SetVisible(false); From 4a89c931fc83b6d31201628050d74a8fe815960b Mon Sep 17 00:00:00 2001 From: Jackson <9527380+Jaksuhn@users.noreply.github.com> Date: Tue, 26 Mar 2024 20:26:49 +0000 Subject: [PATCH 6/6] Update Plugin.cs --- BossMod/Framework/Plugin.cs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/BossMod/Framework/Plugin.cs b/BossMod/Framework/Plugin.cs index e53720ce2..0af3007d1 100644 --- a/BossMod/Framework/Plugin.cs +++ b/BossMod/Framework/Plugin.cs @@ -47,8 +47,6 @@ public Plugin( Service.WindowSystem = new("vbm"); //Service.Device = pluginInterface.UiBuilder.Device; Service.Condition.ConditionChange += OnConditionChanged; - Service.DutyState.DutyStarted += OnDutyStarted; - Service.DutyState.DutyCompleted += OnDutyCompleted; Service.ClientState.TerritoryChanged += OnZoneChange; MultiboxUnlock.Exec(); Network.IDScramble.Initialize(); @@ -86,8 +84,6 @@ public Plugin( public void Dispose() { Service.Condition.ConditionChange -= OnConditionChanged; - Service.DutyState.DutyStarted -= OnDutyStarted; - Service.DutyState.DutyCompleted -= OnDutyCompleted; Service.ClientState.TerritoryChanged -= OnZoneChange; _wndDebug.Dispose(); _wndReplay.Dispose(); @@ -168,18 +164,6 @@ private void OnConditionChanged(ConditionFlag flag, bool value) Service.Log($"Condition chage: {flag}={value}"); } - private void OnDutyStarted(object? sender, ushort e) - { - if (!Service.Config.Get().AutoRecord) return; - _wndReplay.StartRecording(); - } - - private void OnDutyCompleted(object? sender, ushort e) - { - if (!Service.Config.Get().AutoStop) return; - _wndReplay.StopRecording(); - } - private unsafe void OnZoneChange(ushort obj) { if (GameMain.Instance()->CurrentContentFinderConditionId != 0 && !_wndReplay.IsRecording() && Service.Config.Get().AutoRecord)