From 263f311ef8e19af8d18b287d0600b9052786a1e7 Mon Sep 17 00:00:00 2001 From: devoreofox <232652342+devoreofox@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:02:10 -0300 Subject: [PATCH] Add state variables and fix var threading --- CHANGELOG.md | 4 +++ README.md | 2 +- Silkstring/Plugin.cs | 15 ++++++++--- Silkstring/Services/CommandHandler.cs | 2 +- .../Variables/CombatVariablesProvider.cs | 24 ++++++++++++++++++ .../Variables/CurrencyVariablesProvider.cs | 20 +++++++++++++++ .../Variables/VitalsVariablesProvider.cs | 25 +++++++++++++++++++ 7 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 Silkstring/Services/Variables/CombatVariablesProvider.cs create mode 100644 Silkstring/Services/Variables/CurrencyVariablesProvider.cs create mode 100644 Silkstring/Services/Variables/VitalsVariablesProvider.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index f078a10..98da16b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v1.1.0.0 - 2026-06-27 +### Added +- New variables: your HP and MP (including percentages), whether you are in combat, whether you have a target, and your Gil and MGP + ## v1.0.1.0 - 2026-06-26 ### Fixed - Pressing Escape while editing in the multiline command box no longer clears what you typed diff --git a/README.md b/README.md index eb4d772..f53cdfe 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Variables let you insert live game values into a line using curly brace syntax. /say I am {character}, a level {level} {job} from {world}! ``` -Currently supported variables: `{character}`, `{homeworld}`, `{job}`, `{level}`, `{world}`. The Variables tab of the help window lists them with their current values, and the command tester at the top of the help window shows resolved output as you type. +Silkstring includes variables for your character, job, HP and MP, combat state, target, currency, and more, and the list keeps growing. For the full, always-current list with live values, open the Variables tab of the help window (`/silkstring help`). The command tester at the top of that window shows resolved output as you type. ### Parameters diff --git a/Silkstring/Plugin.cs b/Silkstring/Plugin.cs index b24da4b..3817538 100644 --- a/Silkstring/Plugin.cs +++ b/Silkstring/Plugin.cs @@ -17,11 +17,14 @@ namespace Silkstring; public sealed class Plugin : IDalamudPlugin { [PluginService] internal static IDalamudPluginInterface PluginInterface { get; private set; } = null!; - [PluginService] internal static ICommandManager CommandManager { get; private set; } = null!; - [PluginService] internal static IGameInteropProvider GameInteropProvider { get; private set; } = null!; [PluginService] internal static IFramework Framework { get; private set; } = null!; + [PluginService] internal static ICommandManager CommandManager { get; private set; } = null!; [PluginService] internal static INotificationManager NotificationManager { get; private set; } = null!; + [PluginService] internal static ITargetManager TargetManager { get; private set; } = null!; + [PluginService] internal static IGameInteropProvider GameInteropProvider { get; private set; } = null!; [PluginService] internal static IPlayerState PlayerState { get; private set; } = null!; + [PluginService] internal static IClientState ClientState { get; private set; } = null!; + [PluginService] internal static ICondition Condition { get; private set; } = null!; private const string CommandName = "/silkstring"; @@ -57,7 +60,13 @@ public Plugin() ECommonsMain.Init(PluginInterface, this); - IVariableProvider[] providers = [new PlayerVariableProvider(PlayerState)]; + IVariableProvider[] providers = + [ + new PlayerVariableProvider(PlayerState), + new VitalsVariablesProvider(ClientState), + new CombatVariablesProvider(Condition, TargetManager), + new CurrencyVariablesProvider() + ]; _commandResolver = new CommandResolver(providers); _commandHandler = new CommandHandler(_commandResolver, Framework); diff --git a/Silkstring/Services/CommandHandler.cs b/Silkstring/Services/CommandHandler.cs index 052dd31..78d2473 100644 --- a/Silkstring/Services/CommandHandler.cs +++ b/Silkstring/Services/CommandHandler.cs @@ -24,7 +24,7 @@ public async Task ExecuteAsync(IReadOnlyList commands, IReadOnlyList _resolver.Resolve(cmd, args)); if (shouldSkip != null && cmd.StartsWith("/")) { var parts = cmd.TrimStart('/').Split(' ', StringSplitOptions.RemoveEmptyEntries); diff --git a/Silkstring/Services/Variables/CombatVariablesProvider.cs b/Silkstring/Services/Variables/CombatVariablesProvider.cs new file mode 100644 index 0000000..935c035 --- /dev/null +++ b/Silkstring/Services/Variables/CombatVariablesProvider.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Dalamud.Game.ClientState.Conditions; +using Dalamud.Plugin.Services; + +namespace Silkstring.Services.Variables; + +public sealed class CombatVariablesProvider : IVariableProvider +{ + private readonly ICondition _condition; + private readonly ITargetManager _targets; + + public CombatVariablesProvider(ICondition condition, ITargetManager targets) + { + _condition = condition; + _targets = targets; + } + + public IEnumerable GetVariables() + { + yield return new("incombat", "Whether you are in combat", "Combat", () => _condition[ConditionFlag.InCombat] ? "true" : "false"); + + yield return new("hastarget", "Whether you have a target", "Combat", () => _targets.Target != null ? "true" : "false"); + } +} diff --git a/Silkstring/Services/Variables/CurrencyVariablesProvider.cs b/Silkstring/Services/Variables/CurrencyVariablesProvider.cs new file mode 100644 index 0000000..6d386dd --- /dev/null +++ b/Silkstring/Services/Variables/CurrencyVariablesProvider.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using FFXIVClientStructs.FFXIV.Client.Game; + +namespace Silkstring.Services.Variables; + +public sealed class CurrencyVariablesProvider : IVariableProvider +{ + public IEnumerable GetVariables() + { + yield return new("gil", "Your gil", "Currency", () => Count(1)); + yield return new("mgp", "Your MGP", "Currency", () => Count(29)); + } + + private static unsafe string? Count(uint itemId) + { + var inv = InventoryManager.Instance(); + return inv != null ? inv->GetInventoryItemCount(itemId).ToString() : null; + } + +} diff --git a/Silkstring/Services/Variables/VitalsVariablesProvider.cs b/Silkstring/Services/Variables/VitalsVariablesProvider.cs new file mode 100644 index 0000000..a0b91f8 --- /dev/null +++ b/Silkstring/Services/Variables/VitalsVariablesProvider.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Dalamud.Plugin.Services; +using ECommons.DalamudServices.Legacy; + +namespace Silkstring.Services.Variables; + +public sealed class VitalsVariablesProvider : IVariableProvider +{ + private readonly IClientState _clientState; + + public VitalsVariablesProvider(IClientState clientState) => _clientState = clientState; + + public IEnumerable GetVariables() + { + yield return new("hp", "Your current HP", "Vitals", () => _clientState.LocalPlayer?.CurrentHp.ToString()); + yield return new("maxhp", "Your maximum HP", "Vitals", () => _clientState.LocalPlayer?.MaxHp.ToString()); + yield return new("hpp", "Your HP as a percentage", "Vitals", () => Percent(_clientState.LocalPlayer?.CurrentHp, _clientState.LocalPlayer?.MaxHp)); + yield return new("mp", "Your current MP", "Vitals", () => _clientState.LocalPlayer?.CurrentMp.ToString()); + yield return new("maxmp", "Your maximum MP", "Vitals", () => _clientState.LocalPlayer?.MaxMp.ToString()); + yield return new("mpp", "Your MP as a percentage", "Vitals", () => Percent(_clientState.LocalPlayer?.CurrentMp, _clientState.LocalPlayer?.MaxMp)); + } + + private static string? Percent(uint? current, uint? max) => current is {} c && max is {} m && m > 0 ? (c * 100 / m).ToString() : null; + +}